import { f as debug, m as getDefaultExportFromCjs, n as mkdirP, l as exec, w as which, o as warning, i as info, H as HttpCodes, p as HttpClientError, q as HttpClient, t as isDebug, u as setSecret, B as BearerCredentialHandler, e as error } from './cleanup-ChNUL7jL.js'; import * as path from 'path'; import * as fs from 'fs'; import { writeFileSync, existsSync } from 'fs'; import assert$1 from 'assert'; import * as os from 'os'; import { r as requireConcatMap, a as requireDist, b as requireDist$1, c as requireState, d as requireStateCjs } from './state-cjs-BbR-w6pp.js'; import * as crypto$1 from 'crypto'; import * as require$$0$2 from 'stream'; import { Readable } from 'stream'; import * as require$$0$1 from 'util'; import { URL as URL$1 } from 'url'; import require$$0$5, { Transform, Readable as Readable$1 } from 'node:stream'; import { createRequire } from 'node:module'; import { dirname as dirname$1 } from 'node:path'; import { fileURLToPath } from 'node:url'; import * as require$$0$3 from 'buffer'; import { Buffer as Buffer$1 } from 'buffer'; import os$1, { EOL as EOL$1 } from 'node:os'; import require$$1, { inspect } from 'node:util'; import process$1 from 'node:process'; import http from 'node:http'; import https from 'node:https'; import zlib from 'node:zlib'; import { EventEmitter } from 'events'; import require$$0$4 from 'node:buffer'; import { createHmac } from 'node:crypto'; import fs$1 from 'node:fs'; import 'http'; import 'https'; import 'net'; import 'tls'; import 'node:assert'; import 'node:net'; import 'node:querystring'; import 'node:events'; import 'node:diagnostics_channel'; import 'node:tls'; import 'node:perf_hooks'; import 'node:util/types'; import 'node:worker_threads'; import 'node:async_hooks'; import 'node:console'; import 'node:dns'; import 'string_decoder'; import 'child_process'; import 'timers'; import 'fs/promises'; import 'tty'; /** * Returns a copy with defaults filled in. */ function getOptions(copy) { const result = { followSymbolicLinks: true, implicitDescendants: true, matchDirectories: true, omitBrokenSymbolicLinks: true, excludeHiddenFiles: false }; if (copy) { if (typeof copy.followSymbolicLinks === 'boolean') { result.followSymbolicLinks = copy.followSymbolicLinks; debug(`followSymbolicLinks '${result.followSymbolicLinks}'`); } if (typeof copy.implicitDescendants === 'boolean') { result.implicitDescendants = copy.implicitDescendants; debug(`implicitDescendants '${result.implicitDescendants}'`); } if (typeof copy.matchDirectories === 'boolean') { result.matchDirectories = copy.matchDirectories; debug(`matchDirectories '${result.matchDirectories}'`); } if (typeof copy.omitBrokenSymbolicLinks === 'boolean') { result.omitBrokenSymbolicLinks = copy.omitBrokenSymbolicLinks; debug(`omitBrokenSymbolicLinks '${result.omitBrokenSymbolicLinks}'`); } if (typeof copy.excludeHiddenFiles === 'boolean') { result.excludeHiddenFiles = copy.excludeHiddenFiles; debug(`excludeHiddenFiles '${result.excludeHiddenFiles}'`); } } return result; } const IS_WINDOWS$5 = process.platform === 'win32'; /** * Similar to path.dirname except normalizes the path separators and slightly better handling for Windows UNC paths. * * For example, on Linux/macOS: * - `/ => /` * - `/hello => /` * * For example, on Windows: * - `C:\ => C:\` * - `C:\hello => C:\` * - `C: => C:` * - `C:hello => C:` * - `\ => \` * - `\hello => \` * - `\\hello => \\hello` * - `\\hello\world => \\hello\world` */ function dirname(p) { // Normalize slashes and trim unnecessary trailing slash p = safeTrimTrailingSeparator(p); // Windows UNC root, e.g. \\hello or \\hello\world if (IS_WINDOWS$5 && /^\\\\[^\\]+(\\[^\\]+)?$/.test(p)) { return p; } // Get dirname let result = path.dirname(p); // Trim trailing slash for Windows UNC root, e.g. \\hello\world\ if (IS_WINDOWS$5 && /^\\\\[^\\]+\\[^\\]+\\$/.test(result)) { result = safeTrimTrailingSeparator(result); } return result; } /** * Roots the path if not already rooted. On Windows, relative roots like `\` * or `C:` are expanded based on the current working directory. */ function ensureAbsoluteRoot(root, itemPath) { assert$1(root, `ensureAbsoluteRoot parameter 'root' must not be empty`); assert$1(itemPath, `ensureAbsoluteRoot parameter 'itemPath' must not be empty`); // Already rooted if (hasAbsoluteRoot(itemPath)) { return itemPath; } // Windows if (IS_WINDOWS$5) { // Check for itemPath like C: or C:foo if (itemPath.match(/^[A-Z]:[^\\/]|^[A-Z]:$/i)) { let cwd = process.cwd(); assert$1(cwd.match(/^[A-Z]:\\/i), `Expected current directory to start with an absolute drive root. Actual '${cwd}'`); // Drive letter matches cwd? Expand to cwd if (itemPath[0].toUpperCase() === cwd[0].toUpperCase()) { // Drive only, e.g. C: if (itemPath.length === 2) { // Preserve specified drive letter case (upper or lower) return `${itemPath[0]}:\\${cwd.substr(3)}`; } // Drive + path, e.g. C:foo else { if (!cwd.endsWith('\\')) { cwd += '\\'; } // Preserve specified drive letter case (upper or lower) return `${itemPath[0]}:\\${cwd.substr(3)}${itemPath.substr(2)}`; } } // Different drive else { return `${itemPath[0]}:\\${itemPath.substr(2)}`; } } // Check for itemPath like \ or \foo else if (normalizeSeparators(itemPath).match(/^\\$|^\\[^\\]/)) { const cwd = process.cwd(); assert$1(cwd.match(/^[A-Z]:\\/i), `Expected current directory to start with an absolute drive root. Actual '${cwd}'`); return `${cwd[0]}:\\${itemPath.substr(1)}`; } } assert$1(hasAbsoluteRoot(root), `ensureAbsoluteRoot parameter 'root' must have an absolute root`); // Otherwise ensure root ends with a separator if (root.endsWith('/') || (IS_WINDOWS$5 && root.endsWith('\\'))) ; else { // Append separator root += path.sep; } return root + itemPath; } /** * On Linux/macOS, true if path starts with `/`. On Windows, true for paths like: * `\\hello\share` and `C:\hello` (and using alternate separator). */ function hasAbsoluteRoot(itemPath) { assert$1(itemPath, `hasAbsoluteRoot parameter 'itemPath' must not be empty`); // Normalize separators itemPath = normalizeSeparators(itemPath); // Windows if (IS_WINDOWS$5) { // E.g. \\hello\share or C:\hello return itemPath.startsWith('\\\\') || /^[A-Z]:\\/i.test(itemPath); } // E.g. /hello return itemPath.startsWith('/'); } /** * On Linux/macOS, true if path starts with `/`. On Windows, true for paths like: * `\`, `\hello`, `\\hello\share`, `C:`, and `C:\hello` (and using alternate separator). */ function hasRoot(itemPath) { assert$1(itemPath, `isRooted parameter 'itemPath' must not be empty`); // Normalize separators itemPath = normalizeSeparators(itemPath); // Windows if (IS_WINDOWS$5) { // E.g. \ or \hello or \\hello // E.g. C: or C:\hello return itemPath.startsWith('\\') || /^[A-Z]:/i.test(itemPath); } // E.g. /hello return itemPath.startsWith('/'); } /** * Removes redundant slashes and converts `/` to `\` on Windows */ function normalizeSeparators(p) { p = p || ''; // Windows if (IS_WINDOWS$5) { // Convert slashes on Windows p = p.replace(/\//g, '\\'); // Remove redundant slashes const isUnc = /^\\\\+[^\\]/.test(p); // e.g. \\hello return (isUnc ? '\\' : '') + p.replace(/\\\\+/g, '\\'); // preserve leading \\ for UNC } // Remove redundant slashes return p.replace(/\/\/+/g, '/'); } /** * Normalizes the path separators and trims the trailing separator (when safe). * For example, `/foo/ => /foo` but `/ => /` */ function safeTrimTrailingSeparator(p) { // Short-circuit if empty if (!p) { return ''; } // Normalize separators p = normalizeSeparators(p); // No trailing slash if (!p.endsWith(path.sep)) { return p; } // Check '/' on Linux/macOS and '\' on Windows if (p === path.sep) { return p; } // On Windows check if drive root. E.g. C:\ if (IS_WINDOWS$5 && /^[A-Z]:\\$/i.test(p)) { return p; } // Otherwise trim trailing slash return p.substr(0, p.length - 1); } /** * Indicates whether a pattern matches a path */ var MatchKind; (function (MatchKind) { /** Not matched */ MatchKind[MatchKind["None"] = 0] = "None"; /** Matched if the path is a directory */ MatchKind[MatchKind["Directory"] = 1] = "Directory"; /** Matched if the path is a regular file */ MatchKind[MatchKind["File"] = 2] = "File"; /** Matched */ MatchKind[MatchKind["All"] = 3] = "All"; })(MatchKind || (MatchKind = {})); const IS_WINDOWS$4 = process.platform === 'win32'; /** * Given an array of patterns, returns an array of paths to search. * Duplicates and paths under other included paths are filtered out. */ function getSearchPaths(patterns) { // Ignore negate patterns patterns = patterns.filter(x => !x.negate); // Create a map of all search paths const searchPathMap = {}; for (const pattern of patterns) { const key = IS_WINDOWS$4 ? pattern.searchPath.toUpperCase() : pattern.searchPath; searchPathMap[key] = 'candidate'; } const result = []; for (const pattern of patterns) { // Check if already included const key = IS_WINDOWS$4 ? pattern.searchPath.toUpperCase() : pattern.searchPath; if (searchPathMap[key] === 'included') { continue; } // Check for an ancestor search path let foundAncestor = false; let tempKey = key; let parent = dirname(tempKey); while (parent !== tempKey) { if (searchPathMap[parent]) { foundAncestor = true; break; } tempKey = parent; parent = dirname(tempKey); } // Include the search pattern in the result if (!foundAncestor) { result.push(pattern.searchPath); searchPathMap[key] = 'included'; } } return result; } /** * Matches the patterns against the path */ function match(patterns, itemPath) { let result = MatchKind.None; for (const pattern of patterns) { if (pattern.negate) { result &= ~pattern.match(itemPath); } else { result |= pattern.match(itemPath); } } return result; } /** * Checks whether to descend further into the directory */ function partialMatch(patterns, itemPath) { return patterns.some(x => !x.negate && x.partialMatch(itemPath)); } var balancedMatch; var hasRequiredBalancedMatch; function requireBalancedMatch () { if (hasRequiredBalancedMatch) return balancedMatch; hasRequiredBalancedMatch = 1; balancedMatch = balanced; function balanced(a, b, str) { if (a instanceof RegExp) a = maybeMatch(a, str); if (b instanceof RegExp) b = maybeMatch(b, str); var r = range(a, b, str); return r && { start: r[0], end: r[1], pre: str.slice(0, r[0]), body: str.slice(r[0] + a.length, r[1]), post: str.slice(r[1] + b.length) }; } function maybeMatch(reg, str) { var m = str.match(reg); return m ? m[0] : null; } balanced.range = range; function range(a, b, str) { var begs, beg, left, right, result; var ai = str.indexOf(a); var bi = str.indexOf(b, ai + 1); var i = ai; if (ai >= 0 && bi > 0) { if(a===b) { return [ai, bi]; } begs = []; left = str.length; while (i >= 0 && !result) { if (i == ai) { begs.push(i); ai = str.indexOf(a, i + 1); } else if (begs.length == 1) { result = [ begs.pop(), bi ]; } else { beg = begs.pop(); if (beg < left) { left = beg; right = bi; } bi = str.indexOf(b, i + 1); } i = ai < bi && ai >= 0 ? ai : bi; } if (begs.length) { result = [ left, right ]; } } return result; } return balancedMatch; } var braceExpansion; var hasRequiredBraceExpansion; function requireBraceExpansion () { if (hasRequiredBraceExpansion) return braceExpansion; hasRequiredBraceExpansion = 1; var concatMap = requireConcatMap(); var balanced = requireBalancedMatch(); braceExpansion = expandTop; var escSlash = '\0SLASH'+Math.random()+'\0'; var escOpen = '\0OPEN'+Math.random()+'\0'; var escClose = '\0CLOSE'+Math.random()+'\0'; var escComma = '\0COMMA'+Math.random()+'\0'; var escPeriod = '\0PERIOD'+Math.random()+'\0'; function numeric(str) { return parseInt(str, 10) == str ? parseInt(str, 10) : str.charCodeAt(0); } function escapeBraces(str) { return str.split('\\\\').join(escSlash) .split('\\{').join(escOpen) .split('\\}').join(escClose) .split('\\,').join(escComma) .split('\\.').join(escPeriod); } function unescapeBraces(str) { return str.split(escSlash).join('\\') .split(escOpen).join('{') .split(escClose).join('}') .split(escComma).join(',') .split(escPeriod).join('.'); } // Basically just str.split(","), but handling cases // where we have nested braced sections, which should be // treated as individual members, like {a,{b,c},d} function parseCommaParts(str) { if (!str) return ['']; var parts = []; var m = balanced('{', '}', str); if (!m) return str.split(','); var pre = m.pre; var body = m.body; var post = m.post; var p = pre.split(','); p[p.length-1] += '{' + body + '}'; var postParts = parseCommaParts(post); if (post.length) { p[p.length-1] += postParts.shift(); p.push.apply(p, postParts); } parts.push.apply(parts, p); return parts; } function expandTop(str, options) { if (!str) return []; options = options || {}; var max = options.max == null ? Infinity : options.max; // I don't know why Bash 4.3 does this, but it does. // Anything starting with {} will have the first two bytes preserved // but *only* at the top level, so {},a}b will not expand to anything, // but a{},b}c will be expanded to [a}c,abc]. // One could argue that this is a bug in Bash, but since the goal of // this module is to match Bash's rules, we escape a leading {} if (str.substr(0, 2) === '{}') { str = '\\{\\}' + str.substr(2); } return expand(escapeBraces(str), max, true).map(unescapeBraces); } function embrace(str) { return '{' + str + '}'; } function isPadded(el) { return /^-?0\d/.test(el); } function lte(i, y) { return i <= y; } function gte(i, y) { return i >= y; } function expand(str, max, isTop) { var expansions = []; var m = balanced('{', '}', str); if (!m || /\$$/.test(m.pre)) return [str]; var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body); var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body); var isSequence = isNumericSequence || isAlphaSequence; var isOptions = m.body.indexOf(',') >= 0; if (!isSequence && !isOptions) { // {a},b} if (m.post.match(/,(?!,).*\}/)) { str = m.pre + '{' + m.body + escClose + m.post; return expand(str, max, true); } return [str]; } var n; if (isSequence) { n = m.body.split(/\.\./); } else { n = parseCommaParts(m.body); if (n.length === 1) { // x{{a,b}}y ==> x{a}y x{b}y n = expand(n[0], max, false).map(embrace); if (n.length === 1) { var post = m.post.length ? expand(m.post, max, false) : ['']; return post.map(function(p) { return m.pre + n[0] + p; }); } } } // at this point, n is the parts, and we know it's not a comma set // with a single entry. // no need to expand pre, since it is guaranteed to be free of brace-sets var pre = m.pre; var post = m.post.length ? expand(m.post, max, false) : ['']; var N; if (isSequence) { var x = numeric(n[0]); var y = numeric(n[1]); var width = Math.max(n[0].length, n[1].length); var incr = n.length == 3 ? Math.max(Math.abs(numeric(n[2])), 1) : 1; var test = lte; var reverse = y < x; if (reverse) { incr *= -1; test = gte; } var pad = n.some(isPadded); N = []; for (var i = x; test(i, y) && N.length < max; i += incr) { var c; if (isAlphaSequence) { c = String.fromCharCode(i); if (c === '\\') c = ''; } else { c = String(i); if (pad) { var need = width - c.length; if (need > 0) { var z = new Array(need + 1).join('0'); if (i < 0) c = '-' + z + c.slice(1); else c = z + c; } } } N.push(c); } } else { N = concatMap(n, function(el) { return expand(el, max, false) }); } for (var j = 0; j < N.length; j++) { for (var k = 0; k < post.length && expansions.length < max; k++) { var expansion = pre + N[j] + post[k]; if (!isTop || isSequence || expansion) expansions.push(expansion); } } return expansions; } return braceExpansion; } var minimatch_1; var hasRequiredMinimatch; function requireMinimatch () { if (hasRequiredMinimatch) return minimatch_1; hasRequiredMinimatch = 1; minimatch_1 = minimatch; minimatch.Minimatch = Minimatch; var path = (function () { try { return require('path') } catch (e) {}}()) || { sep: '/' }; minimatch.sep = path.sep; var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}; var expand = requireBraceExpansion(); var plTypes = { '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, '?': { open: '(?:', close: ')?' }, '+': { open: '(?:', close: ')+' }, '*': { open: '(?:', close: ')*' }, '@': { open: '(?:', close: ')' } }; // any single thing other than / // don't need to escape / when using new RegExp() var qmark = '[^/]'; // * => any number of characters var star = qmark + '*?'; // ** when dots are allowed. Anything goes, except .. and . // not (^ or / followed by one or two dots followed by $ or /), // followed by anything, any number of times. var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?'; // not a ^ or / followed by a dot, // followed by anything, any number of times. var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?'; // characters that need to be escaped in RegExp. var reSpecials = charSet('().*{}+?[]^$\\!'); // "abc" -> { a:true, b:true, c:true } function charSet (s) { return s.split('').reduce(function (set, c) { set[c] = true; return set }, {}) } // normalizes slashes. var slashSplit = /\/+/; minimatch.filter = filter; function filter (pattern, options) { options = options || {}; return function (p, i, list) { return minimatch(p, pattern, options) } } function ext (a, b) { b = b || {}; var t = {}; Object.keys(a).forEach(function (k) { t[k] = a[k]; }); Object.keys(b).forEach(function (k) { t[k] = b[k]; }); return t } minimatch.defaults = function (def) { if (!def || typeof def !== 'object' || !Object.keys(def).length) { return minimatch } var orig = minimatch; var m = function minimatch (p, pattern, options) { return orig(p, pattern, ext(def, options)) }; m.Minimatch = function Minimatch (pattern, options) { return new orig.Minimatch(pattern, ext(def, options)) }; m.Minimatch.defaults = function defaults (options) { return orig.defaults(ext(def, options)).Minimatch }; m.filter = function filter (pattern, options) { return orig.filter(pattern, ext(def, options)) }; m.defaults = function defaults (options) { return orig.defaults(ext(def, options)) }; m.makeRe = function makeRe (pattern, options) { return orig.makeRe(pattern, ext(def, options)) }; m.braceExpand = function braceExpand (pattern, options) { return orig.braceExpand(pattern, ext(def, options)) }; m.match = function (list, pattern, options) { return orig.match(list, pattern, ext(def, options)) }; return m }; Minimatch.defaults = function (def) { return minimatch.defaults(def).Minimatch }; function minimatch (p, pattern, options) { assertValidPattern(pattern); if (!options) options = {}; // shortcut: comments match nothing. if (!options.nocomment && pattern.charAt(0) === '#') { return false } return new Minimatch(pattern, options).match(p) } function Minimatch (pattern, options) { if (!(this instanceof Minimatch)) { return new Minimatch(pattern, options) } assertValidPattern(pattern); if (!options) options = {}; pattern = pattern.trim(); // windows support: need to use /, not \ if (!options.allowWindowsEscape && path.sep !== '/') { pattern = pattern.split(path.sep).join('/'); } this.options = options; this.maxGlobstarRecursion = options.maxGlobstarRecursion !== undefined ? options.maxGlobstarRecursion : 200; this.set = []; this.pattern = pattern; this.regexp = null; this.negate = false; this.comment = false; this.empty = false; this.partial = !!options.partial; // make the set of regexps etc. this.make(); } Minimatch.prototype.debug = function () {}; Minimatch.prototype.make = make; function make () { var pattern = this.pattern; var options = this.options; // empty patterns and comments match nothing. if (!options.nocomment && pattern.charAt(0) === '#') { this.comment = true; return } if (!pattern) { this.empty = true; return } // step 1: figure out negation, etc. this.parseNegate(); // step 2: expand braces var set = this.globSet = this.braceExpand(); if (options.debug) this.debug = function debug() { console.error.apply(console, arguments); }; this.debug(this.pattern, set); // step 3: now we have a set, so turn each one into a series of path-portion // matching patterns. // These will be regexps, except in the case of "**", which is // set to the GLOBSTAR object for globstar behavior, // and will not contain any / characters set = this.globParts = set.map(function (s) { return s.split(slashSplit) }); this.debug(this.pattern, set); // glob --> regexps set = set.map(function (s, si, set) { return s.map(this.parse, this) }, this); this.debug(this.pattern, set); // filter out everything that didn't compile properly. set = set.filter(function (s) { return s.indexOf(false) === -1 }); this.debug(this.pattern, set); this.set = set; } Minimatch.prototype.parseNegate = parseNegate; function parseNegate () { var pattern = this.pattern; var negate = false; var options = this.options; var negateOffset = 0; if (options.nonegate) return for (var i = 0, l = pattern.length ; i < l && pattern.charAt(i) === '!' ; i++) { negate = !negate; negateOffset++; } if (negateOffset) this.pattern = pattern.substr(negateOffset); this.negate = negate; } // Brace expansion: // a{b,c}d -> abd acd // a{b,}c -> abc ac // a{0..3}d -> a0d a1d a2d a3d // a{b,c{d,e}f}g -> abg acdfg acefg // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg // // Invalid sets are not expanded. // a{2..}b -> a{2..}b // a{b}c -> a{b}c minimatch.braceExpand = function (pattern, options) { return braceExpand(pattern, options) }; Minimatch.prototype.braceExpand = braceExpand; function braceExpand (pattern, options) { if (!options) { if (this instanceof Minimatch) { options = this.options; } else { options = {}; } } pattern = typeof pattern === 'undefined' ? this.pattern : pattern; assertValidPattern(pattern); // Thanks to Yeting Li for // improving this regexp to avoid a ReDOS vulnerability. if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) { // shortcut. no need to expand. return [pattern] } return expand(pattern) } var MAX_PATTERN_LENGTH = 1024 * 64; var assertValidPattern = function (pattern) { if (typeof pattern !== 'string') { throw new TypeError('invalid pattern') } if (pattern.length > MAX_PATTERN_LENGTH) { throw new TypeError('pattern is too long') } }; // parse a component of the expanded set. // At this point, no pattern may contain "/" in it // so we're going to return a 2d array, where each entry is the full // pattern, split on '/', and then turned into a regular expression. // A regexp is made at the end which joins each array with an // escaped /, and another full one which joins each regexp with |. // // Following the lead of Bash 4.1, note that "**" only has special meaning // when it is the *only* thing in a path portion. Otherwise, any series // of * is equivalent to a single *. Globstar behavior is enabled by // default, and can be disabled by setting options.noglobstar. Minimatch.prototype.parse = parse; var SUBPARSE = {}; function parse (pattern, isSub) { assertValidPattern(pattern); var options = this.options; // shortcuts if (pattern === '**') { if (!options.noglobstar) return GLOBSTAR else pattern = '*'; } if (pattern === '') return '' var re = ''; var hasMagic = !!options.nocase; var escaping = false; // ? => one single character var patternListStack = []; var negativeLists = []; var stateChar; var inClass = false; var reClassStart = -1; var classStart = -1; // . and .. never match anything that doesn't start with ., // even when options.dot is set. var patternStart = pattern.charAt(0) === '.' ? '' // anything // not (start or / followed by . or .. followed by / or end) : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))' : '(?!\\.)'; var self = this; function clearStateChar () { if (stateChar) { // we had some state-tracking character // that wasn't consumed by this pass. switch (stateChar) { case '*': re += star; hasMagic = true; break case '?': re += qmark; hasMagic = true; break default: re += '\\' + stateChar; break } self.debug('clearStateChar %j %j', stateChar, re); stateChar = false; } } for (var i = 0, len = pattern.length, c ; (i < len) && (c = pattern.charAt(i)) ; i++) { this.debug('%s\t%s %s %j', pattern, i, re, c); // skip over any that are escaped. if (escaping && reSpecials[c]) { re += '\\' + c; escaping = false; continue } switch (c) { /* istanbul ignore next */ case '/': { // completely not allowed, even escaped. // Should already be path-split by now. return false } case '\\': clearStateChar(); escaping = true; continue // the various stateChar values // for the "extglob" stuff. case '?': case '*': case '+': case '@': case '!': this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c); // all of those are literals inside a class, except that // the glob [!a] means [^a] in regexp if (inClass) { this.debug(' in class'); if (c === '!' && i === classStart + 1) c = '^'; re += c; continue } // coalesce consecutive non-globstar * characters if (c === '*' && stateChar === '*') continue // if we already have a stateChar, then it means // that there was something like ** or +? in there. // Handle the stateChar, then proceed with this one. self.debug('call clearStateChar %j', stateChar); clearStateChar(); stateChar = c; // if extglob is disabled, then +(asdf|foo) isn't a thing. // just clear the statechar *now*, rather than even diving into // the patternList stuff. if (options.noext) clearStateChar(); continue case '(': if (inClass) { re += '('; continue } if (!stateChar) { re += '\\('; continue } patternListStack.push({ type: stateChar, start: i - 1, reStart: re.length, open: plTypes[stateChar].open, close: plTypes[stateChar].close }); // negation is (?:(?!js)[^/]*) re += stateChar === '!' ? '(?:(?!(?:' : '(?:'; this.debug('plType %j %j', stateChar, re); stateChar = false; continue case ')': if (inClass || !patternListStack.length) { re += '\\)'; continue } clearStateChar(); hasMagic = true; var pl = patternListStack.pop(); // negation is (?:(?!js)[^/]*) // The others are (?:) re += pl.close; if (pl.type === '!') { negativeLists.push(pl); } pl.reEnd = re.length; continue case '|': if (inClass || !patternListStack.length || escaping) { re += '\\|'; escaping = false; continue } clearStateChar(); re += '|'; continue // these are mostly the same in regexp and glob case '[': // swallow any state-tracking char before the [ clearStateChar(); if (inClass) { re += '\\' + c; continue } inClass = true; classStart = i; reClassStart = re.length; re += c; continue case ']': // a right bracket shall lose its special // meaning and represent itself in // a bracket expression if it occurs // first in the list. -- POSIX.2 2.8.3.2 if (i === classStart + 1 || !inClass) { re += '\\' + c; escaping = false; continue } // handle the case where we left a class open. // "[z-a]" is valid, equivalent to "\[z-a\]" // split where the last [ was, make sure we don't have // an invalid re. if so, re-walk the contents of the // would-be class to re-translate any characters that // were passed through as-is // TODO: It would probably be faster to determine this // without a try/catch and a new RegExp, but it's tricky // to do safely. For now, this is safe and works. var cs = pattern.substring(classStart + 1, i); try { RegExp('[' + cs + ']'); } catch (er) { // not a valid class! var sp = this.parse(cs, SUBPARSE); re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'; hasMagic = hasMagic || sp[1]; inClass = false; continue } // finish up the class. hasMagic = true; inClass = false; re += c; continue default: // swallow any state char that wasn't consumed clearStateChar(); if (escaping) { // no need escaping = false; } else if (reSpecials[c] && !(c === '^' && inClass)) { re += '\\'; } re += c; } // switch } // for // handle the case where we left a class open. // "[abc" is valid, equivalent to "\[abc" if (inClass) { // split where the last [ was, and escape it // this is a huge pita. We now have to re-walk // the contents of the would-be class to re-translate // any characters that were passed through as-is cs = pattern.substr(classStart + 1); sp = this.parse(cs, SUBPARSE); re = re.substr(0, reClassStart) + '\\[' + sp[0]; hasMagic = hasMagic || sp[1]; } // handle the case where we had a +( thing at the *end* // of the pattern. // each pattern list stack adds 3 chars, and we need to go through // and escape any | chars that were passed through as-is for the regexp. // Go through and escape them, taking care not to double-escape any // | chars that were already escaped. for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { var tail = re.slice(pl.reStart + pl.open.length); this.debug('setting tail', re, pl); // maybe some even number of \, then maybe 1 \, followed by a | tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) { if (!$2) { // the | isn't already escaped, so escape it. $2 = '\\'; } // need to escape all those slashes *again*, without escaping the // one that we need for escaping the | character. As it works out, // escaping an even number of slashes can be done by simply repeating // it exactly after itself. That's why this trick works. // // I am sorry that you have to see this. return $1 + $1 + $2 + '|' }); this.debug('tail=%j\n %s', tail, tail, pl, re); var t = pl.type === '*' ? star : pl.type === '?' ? qmark : '\\' + pl.type; hasMagic = true; re = re.slice(0, pl.reStart) + t + '\\(' + tail; } // handle trailing things that only matter at the very end. clearStateChar(); if (escaping) { // trailing \\ re += '\\\\'; } // only need to apply the nodot start if the re starts with // something that could conceivably capture a dot var addPatternStart = false; switch (re.charAt(0)) { case '[': case '.': case '(': addPatternStart = true; } // Hack to work around lack of negative lookbehind in JS // A pattern like: *.!(x).!(y|z) needs to ensure that a name // like 'a.xyz.yz' doesn't match. So, the first negative // lookahead, has to look ALL the way ahead, to the end of // the pattern. for (var n = negativeLists.length - 1; n > -1; n--) { var nl = negativeLists[n]; var nlBefore = re.slice(0, nl.reStart); var nlFirst = re.slice(nl.reStart, nl.reEnd - 8); var nlLast = re.slice(nl.reEnd - 8, nl.reEnd); var nlAfter = re.slice(nl.reEnd); nlLast += nlAfter; // Handle nested stuff like *(*.js|!(*.json)), where open parens // mean that we should *not* include the ) in the bit that is considered // "after" the negated section. var openParensBefore = nlBefore.split('(').length - 1; var cleanAfter = nlAfter; for (i = 0; i < openParensBefore; i++) { cleanAfter = cleanAfter.replace(/\)[+*?]?/, ''); } nlAfter = cleanAfter; var dollar = ''; if (nlAfter === '' && isSub !== SUBPARSE) { dollar = '$'; } var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast; re = newRe; } // if the re is not "" at this point, then we need to make sure // it doesn't match against an empty path part. // Otherwise a/* will match a/, which it should not. if (re !== '' && hasMagic) { re = '(?=.)' + re; } if (addPatternStart) { re = patternStart + re; } // parsing just a piece of a larger pattern. if (isSub === SUBPARSE) { return [re, hasMagic] } // skip the regexp for non-magical patterns // unescape anything in it, though, so that it'll be // an exact match against a file etc. if (!hasMagic) { return globUnescape(pattern) } var flags = options.nocase ? 'i' : ''; try { var regExp = new RegExp('^' + re + '$', flags); } catch (er) /* istanbul ignore next - should be impossible */ { // If it was an invalid regular expression, then it can't match // anything. This trick looks for a character after the end of // the string, which is of course impossible, except in multi-line // mode, but it's not a /m regex. return new RegExp('$.') } regExp._glob = pattern; regExp._src = re; return regExp } minimatch.makeRe = function (pattern, options) { return new Minimatch(pattern, options || {}).makeRe() }; Minimatch.prototype.makeRe = makeRe; function makeRe () { if (this.regexp || this.regexp === false) return this.regexp // at this point, this.set is a 2d array of partial // pattern strings, or "**". // // It's better to use .match(). This function shouldn't // be used, really, but it's pretty convenient sometimes, // when you just want to work with a regex. var set = this.set; if (!set.length) { this.regexp = false; return this.regexp } var options = this.options; var twoStar = options.noglobstar ? star : options.dot ? twoStarDot : twoStarNoDot; var flags = options.nocase ? 'i' : ''; var re = set.map(function (pattern) { return pattern.map(function (p) { return (p === GLOBSTAR) ? twoStar : (typeof p === 'string') ? regExpEscape(p) : p._src }).join('\\\/') }).join('|'); // must match entire pattern // ending in a * or ** will make it less strict. re = '^(?:' + re + ')$'; // can match anything, as long as it's not this. if (this.negate) re = '^(?!' + re + ').*$'; try { this.regexp = new RegExp(re, flags); } catch (ex) /* istanbul ignore next - should be impossible */ { this.regexp = false; } return this.regexp } minimatch.match = function (list, pattern, options) { options = options || {}; var mm = new Minimatch(pattern, options); list = list.filter(function (f) { return mm.match(f) }); if (mm.options.nonull && !list.length) { list.push(pattern); } return list }; Minimatch.prototype.match = function match (f, partial) { if (typeof partial === 'undefined') partial = this.partial; this.debug('match', f, this.pattern); // short-circuit in the case of busted things. // comments, etc. if (this.comment) return false if (this.empty) return f === '' if (f === '/' && partial) return true var options = this.options; // windows: need to use /, not \ if (path.sep !== '/') { f = f.split(path.sep).join('/'); } // treat the test path as a set of pathparts. f = f.split(slashSplit); this.debug(this.pattern, 'split', f); // just ONE of the pattern sets in this.set needs to match // in order for it to be valid. If negating, then just one // match means that we have failed. // Either way, return on the first hit. var set = this.set; this.debug(this.pattern, 'set', set); // Find the basename of the path by looking for the last non-empty segment var filename; var i; for (i = f.length - 1; i >= 0; i--) { filename = f[i]; if (filename) break } for (i = 0; i < set.length; i++) { var pattern = set[i]; var file = f; if (options.matchBase && pattern.length === 1) { file = [filename]; } var hit = this.matchOne(file, pattern, partial); if (hit) { if (options.flipNegate) return true return !this.negate } } // didn't get any hits. this is success if it's a negative // pattern, failure otherwise. if (options.flipNegate) return false return this.negate }; // set partial to true to test if, for example, // "/a/b" matches the start of "/*/b/*/d" // Partial means, if you run out of file before you run // out of pattern, then that's fine, as long as all // the parts match. Minimatch.prototype.matchOne = function (file, pattern, partial) { if (pattern.indexOf(GLOBSTAR) !== -1) { return this._matchGlobstar(file, pattern, partial, 0, 0) } return this._matchOne(file, pattern, partial, 0, 0) }; Minimatch.prototype._matchGlobstar = function (file, pattern, partial, fileIndex, patternIndex) { var i; // find first globstar from patternIndex var firstgs = -1; for (i = patternIndex; i < pattern.length; i++) { if (pattern[i] === GLOBSTAR) { firstgs = i; break } } // find last globstar var lastgs = -1; for (i = pattern.length - 1; i >= 0; i--) { if (pattern[i] === GLOBSTAR) { lastgs = i; break } } var head = pattern.slice(patternIndex, firstgs); var body = partial ? pattern.slice(firstgs + 1) : pattern.slice(firstgs + 1, lastgs); var tail = partial ? [] : pattern.slice(lastgs + 1); // check the head if (head.length) { var fileHead = file.slice(fileIndex, fileIndex + head.length); if (!this._matchOne(fileHead, head, partial, 0, 0)) { return false } fileIndex += head.length; } // check the tail var fileTailMatch = 0; if (tail.length) { if (tail.length + fileIndex > file.length) return false var tailStart = file.length - tail.length; if (this._matchOne(file, tail, partial, tailStart, 0)) { fileTailMatch = tail.length; } else { // affordance for stuff like a/**/* matching a/b/ if (file[file.length - 1] !== '' || fileIndex + tail.length === file.length) { return false } tailStart--; if (!this._matchOne(file, tail, partial, tailStart, 0)) { return false } fileTailMatch = tail.length + 1; } } // if body is empty (single ** between head and tail) if (!body.length) { var sawSome = !!fileTailMatch; for (i = fileIndex; i < file.length - fileTailMatch; i++) { var f = String(file[i]); sawSome = true; if (f === '.' || f === '..' || (!this.options.dot && f.charAt(0) === '.')) { return false } } return partial || sawSome } // split body into segments at each GLOBSTAR var bodySegments = [[[], 0]]; var currentBody = bodySegments[0]; var nonGsParts = 0; var nonGsPartsSums = [0]; for (var bi = 0; bi < body.length; bi++) { var b = body[bi]; if (b === GLOBSTAR) { nonGsPartsSums.push(nonGsParts); currentBody = [[], 0]; bodySegments.push(currentBody); } else { currentBody[0].push(b); nonGsParts++; } } var idx = bodySegments.length - 1; var fileLength = file.length - fileTailMatch; for (var si = 0; si < bodySegments.length; si++) { bodySegments[si][1] = fileLength - (nonGsPartsSums[idx--] + bodySegments[si][0].length); } return !!this._matchGlobStarBodySections( file, bodySegments, fileIndex, 0, partial, 0, !!fileTailMatch ) }; // return false for "nope, not matching" // return null for "not matching, cannot keep trying" Minimatch.prototype._matchGlobStarBodySections = function ( file, bodySegments, fileIndex, bodyIndex, partial, globStarDepth, sawTail ) { var bs = bodySegments[bodyIndex]; if (!bs) { // just make sure there are no bad dots for (var i = fileIndex; i < file.length; i++) { sawTail = true; var f = file[i]; if (f === '.' || f === '..' || (!this.options.dot && f.charAt(0) === '.')) { return false } } return sawTail } var body = bs[0]; var after = bs[1]; while (fileIndex <= after) { var m = this._matchOne( file.slice(0, fileIndex + body.length), body, partial, fileIndex, 0 ); // if limit exceeded, no match. intentional false negative, // acceptable break in correctness for security. if (m && globStarDepth < this.maxGlobstarRecursion) { var sub = this._matchGlobStarBodySections( file, bodySegments, fileIndex + body.length, bodyIndex + 1, partial, globStarDepth + 1, sawTail ); if (sub !== false) { return sub } } var f = file[fileIndex]; if (f === '.' || f === '..' || (!this.options.dot && f.charAt(0) === '.')) { return false } fileIndex++; } return partial || null }; Minimatch.prototype._matchOne = function (file, pattern, partial, fileIndex, patternIndex) { var fi, pi, fl, pl; for ( fi = fileIndex, pi = patternIndex, fl = file.length, pl = pattern.length ; (fi < fl) && (pi < pl) ; fi++, pi++ ) { this.debug('matchOne loop'); var p = pattern[pi]; var f = file[fi]; this.debug(pattern, p, f); // should be impossible. // some invalid regexp stuff in the set. /* istanbul ignore if */ if (p === false || p === GLOBSTAR) return false // something other than ** // non-magic patterns just have to match exactly // patterns with magic have been turned into regexps. var hit; if (typeof p === 'string') { hit = f === p; this.debug('string match', p, f, hit); } else { hit = f.match(p); this.debug('pattern match', p, f, hit); } if (!hit) return false } // now either we fell off the end of the pattern, or we're done. if (fi === fl && pi === pl) { // ran out of pattern and filename at the same time. // an exact hit! return true } else if (fi === fl) { // ran out of file, but still had pattern left. // this is ok if we're doing the match as part of // a glob fs traversal. return partial } else /* istanbul ignore else */ if (pi === pl) { // ran out of pattern, still have file left. // this is only acceptable if we're on the very last // empty segment of a file with a trailing slash. // a/* should match a/b/ return (fi === fl - 1) && (file[fi] === '') } // should be unreachable. /* istanbul ignore next */ throw new Error('wtf?') }; // replace stuff like \* with * function globUnescape (s) { return s.replace(/\\(.)/g, '$1') } function regExpEscape (s) { return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') } return minimatch_1; } var minimatchExports = requireMinimatch(); var minimatch = /*@__PURE__*/getDefaultExportFromCjs(minimatchExports); const IS_WINDOWS$3 = process.platform === 'win32'; /** * Helper class for parsing paths into segments */ class Path { /** * Constructs a Path * @param itemPath Path or array of segments */ constructor(itemPath) { this.segments = []; // String if (typeof itemPath === 'string') { assert$1(itemPath, `Parameter 'itemPath' must not be empty`); // Normalize slashes and trim unnecessary trailing slash itemPath = safeTrimTrailingSeparator(itemPath); // Not rooted if (!hasRoot(itemPath)) { this.segments = itemPath.split(path.sep); } // Rooted else { // Add all segments, while not at the root let remaining = itemPath; let dir = dirname(remaining); while (dir !== remaining) { // Add the segment const basename = path.basename(remaining); this.segments.unshift(basename); // Truncate the last segment remaining = dir; dir = dirname(remaining); } // Remainder is the root this.segments.unshift(remaining); } } // Array else { // Must not be empty assert$1(itemPath.length > 0, `Parameter 'itemPath' must not be an empty array`); // Each segment for (let i = 0; i < itemPath.length; i++) { let segment = itemPath[i]; // Must not be empty assert$1(segment, `Parameter 'itemPath' must not contain any empty segments`); // Normalize slashes segment = normalizeSeparators(itemPath[i]); // Root segment if (i === 0 && hasRoot(segment)) { segment = safeTrimTrailingSeparator(segment); assert$1(segment === dirname(segment), `Parameter 'itemPath' root segment contains information for multiple segments`); this.segments.push(segment); } // All other segments else { // Must not contain slash assert$1(!segment.includes(path.sep), `Parameter 'itemPath' contains unexpected path separators`); this.segments.push(segment); } } } } /** * Converts the path to it's string representation */ toString() { // First segment let result = this.segments[0]; // All others let skipSlash = result.endsWith(path.sep) || (IS_WINDOWS$3 && /^[A-Z]:$/i.test(result)); for (let i = 1; i < this.segments.length; i++) { if (skipSlash) { skipSlash = false; } else { result += path.sep; } result += this.segments[i]; } return result; } } const { Minimatch } = minimatch; const IS_WINDOWS$2 = process.platform === 'win32'; class Pattern { constructor(patternOrNegate, isImplicitPattern = false, segments, homedir) { /** * Indicates whether matches should be excluded from the result set */ this.negate = false; // Pattern overload let pattern; if (typeof patternOrNegate === 'string') { pattern = patternOrNegate.trim(); } // Segments overload else { // Convert to pattern segments = segments || []; assert$1(segments.length, `Parameter 'segments' must not empty`); const root = Pattern.getLiteral(segments[0]); assert$1(root && hasAbsoluteRoot(root), `Parameter 'segments' first element must be a root path`); pattern = new Path(segments).toString().trim(); if (patternOrNegate) { pattern = `!${pattern}`; } } // Negate while (pattern.startsWith('!')) { this.negate = !this.negate; pattern = pattern.substr(1).trim(); } // Normalize slashes and ensures absolute root pattern = Pattern.fixupPattern(pattern, homedir); // Segments this.segments = new Path(pattern).segments; // Trailing slash indicates the pattern should only match directories, not regular files this.trailingSeparator = normalizeSeparators(pattern) .endsWith(path.sep); pattern = safeTrimTrailingSeparator(pattern); // Search path (literal path prior to the first glob segment) let foundGlob = false; const searchSegments = this.segments .map(x => Pattern.getLiteral(x)) .filter(x => !foundGlob && !(foundGlob = x === '')); this.searchPath = new Path(searchSegments).toString(); // Root RegExp (required when determining partial match) this.rootRegExp = new RegExp(Pattern.regExpEscape(searchSegments[0]), IS_WINDOWS$2 ? 'i' : ''); this.isImplicitPattern = isImplicitPattern; // Create minimatch const minimatchOptions = { dot: true, nobrace: true, nocase: IS_WINDOWS$2, nocomment: true, noext: true, nonegate: true }; pattern = IS_WINDOWS$2 ? pattern.replace(/\\/g, '/') : pattern; this.minimatch = new Minimatch(pattern, minimatchOptions); } /** * Matches the pattern against the specified path */ match(itemPath) { // Last segment is globstar? if (this.segments[this.segments.length - 1] === '**') { // Normalize slashes itemPath = normalizeSeparators(itemPath); // Append a trailing slash. Otherwise Minimatch will not match the directory immediately // preceding the globstar. For example, given the pattern `/foo/**`, Minimatch returns // false for `/foo` but returns true for `/foo/`. Append a trailing slash to handle that quirk. if (!itemPath.endsWith(path.sep) && this.isImplicitPattern === false) { // Note, this is safe because the constructor ensures the pattern has an absolute root. // For example, formats like C: and C:foo on Windows are resolved to an absolute root. itemPath = `${itemPath}${path.sep}`; } } else { // Normalize slashes and trim unnecessary trailing slash itemPath = safeTrimTrailingSeparator(itemPath); } // Match if (this.minimatch.match(itemPath)) { return this.trailingSeparator ? MatchKind.Directory : MatchKind.All; } return MatchKind.None; } /** * Indicates whether the pattern may match descendants of the specified path */ partialMatch(itemPath) { // Normalize slashes and trim unnecessary trailing slash itemPath = safeTrimTrailingSeparator(itemPath); // matchOne does not handle root path correctly if (dirname(itemPath) === itemPath) { return this.rootRegExp.test(itemPath); } return this.minimatch.matchOne(itemPath.split(IS_WINDOWS$2 ? /\\+/ : /\/+/), this.minimatch.set[0], true); } /** * Escapes glob patterns within a path */ static globEscape(s) { return (IS_WINDOWS$2 ? s : s.replace(/\\/g, '\\\\')) // escape '\' on Linux/macOS .replace(/(\[)(?=[^/]+\])/g, '[[]') // escape '[' when ']' follows within the path segment .replace(/\?/g, '[?]') // escape '?' .replace(/\*/g, '[*]'); // escape '*' } /** * Normalizes slashes and ensures absolute root */ static fixupPattern(pattern, homedir) { // Empty assert$1(pattern, 'pattern cannot be empty'); // Must not contain `.` segment, unless first segment // Must not contain `..` segment const literalSegments = new Path(pattern).segments.map(x => Pattern.getLiteral(x)); assert$1(literalSegments.every((x, i) => (x !== '.' || i === 0) && x !== '..'), `Invalid pattern '${pattern}'. Relative pathing '.' and '..' is not allowed.`); // Must not contain globs in root, e.g. Windows UNC path \\foo\b*r assert$1(!hasRoot(pattern) || literalSegments[0], `Invalid pattern '${pattern}'. Root segment must not contain globs.`); // Normalize slashes pattern = normalizeSeparators(pattern); // Replace leading `.` segment if (pattern === '.' || pattern.startsWith(`.${path.sep}`)) { pattern = Pattern.globEscape(process.cwd()) + pattern.substr(1); } // Replace leading `~` segment else if (pattern === '~' || pattern.startsWith(`~${path.sep}`)) { homedir = homedir || os.homedir(); assert$1(homedir, 'Unable to determine HOME directory'); assert$1(hasAbsoluteRoot(homedir), `Expected HOME directory to be a rooted path. Actual '${homedir}'`); pattern = Pattern.globEscape(homedir) + pattern.substr(1); } // Replace relative drive root, e.g. pattern is C: or C:foo else if (IS_WINDOWS$2 && (pattern.match(/^[A-Z]:$/i) || pattern.match(/^[A-Z]:[^\\]/i))) { let root = ensureAbsoluteRoot('C:\\dummy-root', pattern.substr(0, 2)); if (pattern.length > 2 && !root.endsWith('\\')) { root += '\\'; } pattern = Pattern.globEscape(root) + pattern.substr(2); } // Replace relative root, e.g. pattern is \ or \foo else if (IS_WINDOWS$2 && (pattern === '\\' || pattern.match(/^\\[^\\]/))) { let root = ensureAbsoluteRoot('C:\\dummy-root', '\\'); if (!root.endsWith('\\')) { root += '\\'; } pattern = Pattern.globEscape(root) + pattern.substr(1); } // Otherwise ensure absolute root else { pattern = ensureAbsoluteRoot(Pattern.globEscape(process.cwd()), pattern); } return normalizeSeparators(pattern); } /** * Attempts to unescape a pattern segment to create a literal path segment. * Otherwise returns empty string. */ static getLiteral(segment) { let literal = ''; for (let i = 0; i < segment.length; i++) { const c = segment[i]; // Escape if (c === '\\' && !IS_WINDOWS$2 && i + 1 < segment.length) { literal += segment[++i]; continue; } // Wildcard else if (c === '*' || c === '?') { return ''; } // Character set else if (c === '[' && i + 1 < segment.length) { let set = ''; let closed = -1; for (let i2 = i + 1; i2 < segment.length; i2++) { const c2 = segment[i2]; // Escape if (c2 === '\\' && !IS_WINDOWS$2 && i2 + 1 < segment.length) { set += segment[++i2]; continue; } // Closed else if (c2 === ']') { closed = i2; break; } // Otherwise else { set += c2; } } // Closed? if (closed >= 0) { // Cannot convert if (set.length > 1) { return ''; } // Convert to literal if (set) { literal += set; i = closed; continue; } } // Otherwise fall thru } // Append literal += c; } return literal; } /** * Escapes regexp special characters * https://javascript.info/regexp-escaping */ static regExpEscape(s) { return s.replace(/[[\\^$.|?*+()]/g, '\\$&'); } } class SearchState { constructor(path, level) { this.path = path; this.level = level; } } var __awaiter$9 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __asyncValues$1 = (undefined && undefined.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; var __await = (undefined && undefined.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }; var __asyncGenerator = (undefined && undefined.__asyncGenerator) || function (thisArg, _arguments, generator) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var g = generator.apply(thisArg, _arguments || []), i, q = []; return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; } function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } } function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } }; const IS_WINDOWS$1 = process.platform === 'win32'; class DefaultGlobber { constructor(options) { this.patterns = []; this.searchPaths = []; this.options = getOptions(options); } getSearchPaths() { // Return a copy return this.searchPaths.slice(); } glob() { return __awaiter$9(this, void 0, void 0, function* () { var _a, e_1, _b, _c; const result = []; try { for (var _d = true, _e = __asyncValues$1(this.globGenerator()), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) { _c = _f.value; _d = false; const itemPath = _c; result.push(itemPath); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_d && !_a && (_b = _e.return)) yield _b.call(_e); } finally { if (e_1) throw e_1.error; } } return result; }); } globGenerator() { return __asyncGenerator(this, arguments, function* globGenerator_1() { // Fill in defaults options const options = getOptions(this.options); // Implicit descendants? const patterns = []; for (const pattern of this.patterns) { patterns.push(pattern); if (options.implicitDescendants && (pattern.trailingSeparator || pattern.segments[pattern.segments.length - 1] !== '**')) { patterns.push(new Pattern(pattern.negate, true, pattern.segments.concat('**'))); } } // Push the search paths const stack = []; for (const searchPath of getSearchPaths(patterns)) { debug(`Search path '${searchPath}'`); // Exists? try { // Intentionally using lstat. Detection for broken symlink // will be performed later (if following symlinks). yield __await(fs.promises.lstat(searchPath)); } catch (err) { if (err.code === 'ENOENT') { continue; } throw err; } stack.unshift(new SearchState(searchPath, 1)); } // Search const traversalChain = []; // used to detect cycles while (stack.length) { // Pop const item = stack.pop(); // Match? const match$1 = match(patterns, item.path); const partialMatch$1 = !!match$1 || partialMatch(patterns, item.path); if (!match$1 && !partialMatch$1) { continue; } // Stat const stats = yield __await(DefaultGlobber.stat(item, options, traversalChain) // Broken symlink, or symlink cycle detected, or no longer exists ); // Broken symlink, or symlink cycle detected, or no longer exists if (!stats) { continue; } // Hidden file or directory? if (options.excludeHiddenFiles && path.basename(item.path).match(/^\./)) { continue; } // Directory if (stats.isDirectory()) { // Matched if (match$1 & MatchKind.Directory && options.matchDirectories) { yield yield __await(item.path); } // Descend? else if (!partialMatch$1) { continue; } // Push the child items in reverse const childLevel = item.level + 1; const childItems = (yield __await(fs.promises.readdir(item.path))).map(x => new SearchState(path.join(item.path, x), childLevel)); stack.push(...childItems.reverse()); } // File else if (match$1 & MatchKind.File) { yield yield __await(item.path); } } }); } /** * Constructs a DefaultGlobber */ static create(patterns, options) { return __awaiter$9(this, void 0, void 0, function* () { const result = new DefaultGlobber(options); if (IS_WINDOWS$1) { patterns = patterns.replace(/\r\n/g, '\n'); patterns = patterns.replace(/\r/g, '\n'); } const lines = patterns.split('\n').map(x => x.trim()); for (const line of lines) { // Empty or comment if (!line || line.startsWith('#')) { continue; } // Pattern else { result.patterns.push(new Pattern(line)); } } result.searchPaths.push(...getSearchPaths(result.patterns)); return result; }); } static stat(item, options, traversalChain) { return __awaiter$9(this, void 0, void 0, function* () { // Note: // `stat` returns info about the target of a symlink (or symlink chain) // `lstat` returns info about a symlink itself let stats; if (options.followSymbolicLinks) { try { // Use `stat` (following symlinks) stats = yield fs.promises.stat(item.path); } catch (err) { if (err.code === 'ENOENT') { if (options.omitBrokenSymbolicLinks) { debug(`Broken symlink '${item.path}'`); return undefined; } throw new Error(`No information found for the path '${item.path}'. This may indicate a broken symbolic link.`); } throw err; } } else { // Use `lstat` (not following symlinks) stats = yield fs.promises.lstat(item.path); } // Note, isDirectory() returns false for the lstat of a symlink if (stats.isDirectory() && options.followSymbolicLinks) { // Get the realpath const realPath = yield fs.promises.realpath(item.path); // Fixup the traversal chain to match the item level while (traversalChain.length >= item.level) { traversalChain.pop(); } // Test for a cycle if (traversalChain.some((x) => x === realPath)) { debug(`Symlink cycle detected for path '${item.path}' and realpath '${realPath}'`); return undefined; } // Update the traversal chain traversalChain.push(realPath); } return stats; }); } } (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; (undefined && undefined.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; var __awaiter$8 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * Constructs a globber * * @param patterns Patterns separated by newlines * @param options Glob options */ function create(patterns, options) { return __awaiter$8(this, void 0, void 0, function* () { return yield DefaultGlobber.create(patterns, options); }); } var re = {exports: {}}; var constants; var hasRequiredConstants; function requireConstants () { if (hasRequiredConstants) return constants; hasRequiredConstants = 1; // Note: this is the semver.org version of the spec that it implements // Not necessarily the package version of this code. const SEMVER_SPEC_VERSION = '2.0.0'; const MAX_LENGTH = 256; const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || /* istanbul ignore next */ 9007199254740991; // Max safe segment length for coercion. const MAX_SAFE_COMPONENT_LENGTH = 16; // Max safe length for a build identifier. The max length minus 6 characters for // the shortest version with a build 0.0.0+BUILD. const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6; const RELEASE_TYPES = [ 'major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease', ]; constants = { MAX_LENGTH, MAX_SAFE_COMPONENT_LENGTH, MAX_SAFE_BUILD_LENGTH, MAX_SAFE_INTEGER, RELEASE_TYPES, SEMVER_SPEC_VERSION, FLAG_INCLUDE_PRERELEASE: 0b001, FLAG_LOOSE: 0b010, }; return constants; } var debug_1; var hasRequiredDebug; function requireDebug () { if (hasRequiredDebug) return debug_1; hasRequiredDebug = 1; const debug = ( typeof process === 'object' && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG) ) ? (...args) => console.error('SEMVER', ...args) : () => {}; debug_1 = debug; return debug_1; } var hasRequiredRe; function requireRe () { if (hasRequiredRe) return re.exports; hasRequiredRe = 1; (function (module, exports) { const { MAX_SAFE_COMPONENT_LENGTH, MAX_SAFE_BUILD_LENGTH, MAX_LENGTH, } = requireConstants(); const debug = requireDebug(); exports = module.exports = {}; // The actual regexps go on exports.re const re = exports.re = []; const safeRe = exports.safeRe = []; const src = exports.src = []; const safeSrc = exports.safeSrc = []; const t = exports.t = {}; let R = 0; const LETTERDASHNUMBER = '[a-zA-Z0-9-]'; // Replace some greedy regex tokens to prevent regex dos issues. These regex are // used internally via the safeRe object since all inputs in this library get // normalized first to trim and collapse all extra whitespace. The original // regexes are exported for userland consumption and lower level usage. A // future breaking change could export the safer regex only with a note that // all input should have extra whitespace removed. const safeRegexReplacements = [ ['\\s', 1], ['\\d', MAX_LENGTH], [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH], ]; const makeSafeRegex = (value) => { for (const [token, max] of safeRegexReplacements) { value = value .split(`${token}*`).join(`${token}{0,${max}}`) .split(`${token}+`).join(`${token}{1,${max}}`); } return value }; const createToken = (name, value, isGlobal) => { const safe = makeSafeRegex(value); const index = R++; debug(name, index, value); t[name] = index; src[index] = value; safeSrc[index] = safe; re[index] = new RegExp(value, isGlobal ? 'g' : undefined); safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined); }; // The following Regular Expressions can be used for tokenizing, // validating, and parsing SemVer version strings. // ## Numeric Identifier // A single `0`, or a non-zero digit followed by zero or more digits. createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*'); createToken('NUMERICIDENTIFIERLOOSE', '\\d+'); // ## Non-numeric Identifier // Zero or more digits, followed by a letter or hyphen, and then zero or // more letters, digits, or hyphens. createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`); // ## Main Version // Three dot-separated numeric identifiers. createToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` + `(${src[t.NUMERICIDENTIFIER]})\\.` + `(${src[t.NUMERICIDENTIFIER]})`); createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + `(${src[t.NUMERICIDENTIFIERLOOSE]})`); // ## Pre-release Version Identifier // A numeric identifier, or a non-numeric identifier. // Non-numeric identifiers include numeric identifiers but can be longer. // Therefore non-numeric identifiers must go first. createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER] }|${src[t.NUMERICIDENTIFIER]})`); createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER] }|${src[t.NUMERICIDENTIFIERLOOSE]})`); // ## Pre-release Version // Hyphen, followed by one or more dot-separated pre-release version // identifiers. createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER] }(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`); createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE] }(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`); // ## Build Metadata Identifier // Any combination of digits, letters, or hyphens. createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`); // ## Build Metadata // Plus sign, followed by one or more period-separated build metadata // identifiers. createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER] }(?:\\.${src[t.BUILDIDENTIFIER]})*))`); // ## Full Version String // A main version, followed optionally by a pre-release version and // build metadata. // Note that the only major, minor, patch, and pre-release sections of // the version string are capturing groups. The build metadata is not a // capturing group, because it should not ever be used in version // comparison. createToken('FULLPLAIN', `v?${src[t.MAINVERSION] }${src[t.PRERELEASE]}?${ src[t.BUILD]}?`); createToken('FULL', `^${src[t.FULLPLAIN]}$`); // like full, but allows v1.2.3 and =1.2.3, which people do sometimes. // also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty // common in the npm registry. createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE] }${src[t.PRERELEASELOOSE]}?${ src[t.BUILD]}?`); createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`); createToken('GTLT', '((?:<|>)?=?)'); // Something like "2.*" or "1.2.x". // Note that "x.x" is a valid xRange identifier, meaning "any version" // Only the first item is strictly required. createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`); createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`); createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` + `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + `(?:${src[t.PRERELEASE]})?${ src[t.BUILD]}?` + `)?)?`); createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` + `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + `(?:${src[t.PRERELEASELOOSE]})?${ src[t.BUILD]}?` + `)?)?`); createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`); createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`); // Coercion. // Extract anything that could conceivably be a part of a valid semver createToken('COERCEPLAIN', `${'(^|[^\\d])' + '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`); createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`); createToken('COERCEFULL', src[t.COERCEPLAIN] + `(?:${src[t.PRERELEASE]})?` + `(?:${src[t.BUILD]})?` + `(?:$|[^\\d])`); createToken('COERCERTL', src[t.COERCE], true); createToken('COERCERTLFULL', src[t.COERCEFULL], true); // Tilde ranges. // Meaning is "reasonably at or greater than" createToken('LONETILDE', '(?:~>?)'); createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true); exports.tildeTrimReplace = '$1~'; createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`); createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`); // Caret ranges. // Meaning is "at least and backwards compatible with" createToken('LONECARET', '(?:\\^)'); createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true); exports.caretTrimReplace = '$1^'; createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`); createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`); // A simple gt/lt/eq thing, or just "" to indicate "any version" createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`); createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`); // An expression to strip any whitespace between the gtlt and the thing // it modifies, so that `> 1.2.3` ==> `>1.2.3` createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT] }\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true); exports.comparatorTrimReplace = '$1$2$3'; // Something like `1.2.3 - 1.2.4` // Note that these all use the loose form, because they'll be // checked against either the strict or loose comparator form // later. createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` + `\\s+-\\s+` + `(${src[t.XRANGEPLAIN]})` + `\\s*$`); createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` + `\\s+-\\s+` + `(${src[t.XRANGEPLAINLOOSE]})` + `\\s*$`); // Star ranges basically just allow anything at all. createToken('STAR', '(<|>)?=?\\s*\\*'); // >=0.0.0 is like a star createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$'); createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$'); } (re, re.exports)); return re.exports; } var parseOptions_1; var hasRequiredParseOptions; function requireParseOptions () { if (hasRequiredParseOptions) return parseOptions_1; hasRequiredParseOptions = 1; // parse out just the options we care about const looseOption = Object.freeze({ loose: true }); const emptyOpts = Object.freeze({ }); const parseOptions = options => { if (!options) { return emptyOpts } if (typeof options !== 'object') { return looseOption } return options }; parseOptions_1 = parseOptions; return parseOptions_1; } var identifiers; var hasRequiredIdentifiers; function requireIdentifiers () { if (hasRequiredIdentifiers) return identifiers; hasRequiredIdentifiers = 1; const numeric = /^[0-9]+$/; const compareIdentifiers = (a, b) => { if (typeof a === 'number' && typeof b === 'number') { return a === b ? 0 : a < b ? -1 : 1 } const anum = numeric.test(a); const bnum = numeric.test(b); if (anum && bnum) { a = +a; b = +b; } return a === b ? 0 : (anum && !bnum) ? -1 : (bnum && !anum) ? 1 : a < b ? -1 : 1 }; const rcompareIdentifiers = (a, b) => compareIdentifiers(b, a); identifiers = { compareIdentifiers, rcompareIdentifiers, }; return identifiers; } var semver$1; var hasRequiredSemver$1; function requireSemver$1 () { if (hasRequiredSemver$1) return semver$1; hasRequiredSemver$1 = 1; const debug = requireDebug(); const { MAX_LENGTH, MAX_SAFE_INTEGER } = requireConstants(); const { safeRe: re, t } = requireRe(); const parseOptions = requireParseOptions(); const { compareIdentifiers } = requireIdentifiers(); const isPrereleaseIdentifier = (prerelease, identifier) => { const identifiers = identifier.split('.'); if (identifiers.length > prerelease.length) { return false } for (let i = 0; i < identifiers.length; i++) { if (compareIdentifiers(prerelease[i], identifiers[i]) !== 0) { return false } } return true }; class SemVer { constructor (version, options) { options = parseOptions(options); if (version instanceof SemVer) { if (version.loose === !!options.loose && version.includePrerelease === !!options.includePrerelease) { return version } else { version = version.version; } } else if (typeof version !== 'string') { throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`) } if (version.length > MAX_LENGTH) { throw new TypeError( `version is longer than ${MAX_LENGTH} characters` ) } debug('SemVer', version, options); this.options = options; this.loose = !!options.loose; // this isn't actually relevant for versions, but keep it so that we // don't run into trouble passing this.options around. this.includePrerelease = !!options.includePrerelease; const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]); if (!m) { throw new TypeError(`Invalid Version: ${version}`) } this.raw = version; // these are actually numbers this.major = +m[1]; this.minor = +m[2]; this.patch = +m[3]; if (this.major > MAX_SAFE_INTEGER || this.major < 0) { throw new TypeError('Invalid major version') } if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { throw new TypeError('Invalid minor version') } if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { throw new TypeError('Invalid patch version') } // numberify any prerelease numeric ids if (!m[4]) { this.prerelease = []; } else { this.prerelease = m[4].split('.').map((id) => { if (/^[0-9]+$/.test(id)) { const num = +id; if (num >= 0 && num < MAX_SAFE_INTEGER) { return num } } return id }); } this.build = m[5] ? m[5].split('.') : []; this.format(); } format () { this.version = `${this.major}.${this.minor}.${this.patch}`; if (this.prerelease.length) { this.version += `-${this.prerelease.join('.')}`; } return this.version } toString () { return this.version } compare (other) { debug('SemVer.compare', this.version, this.options, other); if (!(other instanceof SemVer)) { if (typeof other === 'string' && other === this.version) { return 0 } other = new SemVer(other, this.options); } if (other.version === this.version) { return 0 } return this.compareMain(other) || this.comparePre(other) } compareMain (other) { if (!(other instanceof SemVer)) { other = new SemVer(other, this.options); } if (this.major < other.major) { return -1 } if (this.major > other.major) { return 1 } if (this.minor < other.minor) { return -1 } if (this.minor > other.minor) { return 1 } if (this.patch < other.patch) { return -1 } if (this.patch > other.patch) { return 1 } return 0 } comparePre (other) { if (!(other instanceof SemVer)) { other = new SemVer(other, this.options); } // NOT having a prerelease is > having one if (this.prerelease.length && !other.prerelease.length) { return -1 } else if (!this.prerelease.length && other.prerelease.length) { return 1 } else if (!this.prerelease.length && !other.prerelease.length) { return 0 } let i = 0; do { const a = this.prerelease[i]; const b = other.prerelease[i]; debug('prerelease compare', i, a, b); if (a === undefined && b === undefined) { return 0 } else if (b === undefined) { return 1 } else if (a === undefined) { return -1 } else if (a === b) { continue } else { return compareIdentifiers(a, b) } } while (++i) } compareBuild (other) { if (!(other instanceof SemVer)) { other = new SemVer(other, this.options); } let i = 0; do { const a = this.build[i]; const b = other.build[i]; debug('build compare', i, a, b); if (a === undefined && b === undefined) { return 0 } else if (b === undefined) { return 1 } else if (a === undefined) { return -1 } else if (a === b) { continue } else { return compareIdentifiers(a, b) } } while (++i) } // preminor will bump the version up to the next minor release, and immediately // down to pre-release. premajor and prepatch work the same way. inc (release, identifier, identifierBase) { if (release.startsWith('pre')) { if (!identifier && identifierBase === false) { throw new Error('invalid increment argument: identifier is empty') } // Avoid an invalid semver results if (identifier) { const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE]); if (!match || match[1] !== identifier) { throw new Error(`invalid identifier: ${identifier}`) } } } switch (release) { case 'premajor': this.prerelease.length = 0; this.patch = 0; this.minor = 0; this.major++; this.inc('pre', identifier, identifierBase); break case 'preminor': this.prerelease.length = 0; this.patch = 0; this.minor++; this.inc('pre', identifier, identifierBase); break case 'prepatch': // If this is already a prerelease, it will bump to the next version // drop any prereleases that might already exist, since they are not // relevant at this point. this.prerelease.length = 0; this.inc('patch', identifier, identifierBase); this.inc('pre', identifier, identifierBase); break // If the input is a non-prerelease version, this acts the same as // prepatch. case 'prerelease': if (this.prerelease.length === 0) { this.inc('patch', identifier, identifierBase); } this.inc('pre', identifier, identifierBase); break case 'release': if (this.prerelease.length === 0) { throw new Error(`version ${this.raw} is not a prerelease`) } this.prerelease.length = 0; break case 'major': // If this is a pre-major version, bump up to the same major version. // Otherwise increment major. // 1.0.0-5 bumps to 1.0.0 // 1.1.0 bumps to 2.0.0 if ( this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0 ) { this.major++; } this.minor = 0; this.patch = 0; this.prerelease = []; break case 'minor': // If this is a pre-minor version, bump up to the same minor version. // Otherwise increment minor. // 1.2.0-5 bumps to 1.2.0 // 1.2.1 bumps to 1.3.0 if (this.patch !== 0 || this.prerelease.length === 0) { this.minor++; } this.patch = 0; this.prerelease = []; break case 'patch': // If this is not a pre-release version, it will increment the patch. // If it is a pre-release it will bump up to the same patch version. // 1.2.0-5 patches to 1.2.0 // 1.2.0 patches to 1.2.1 if (this.prerelease.length === 0) { this.patch++; } this.prerelease = []; break // This probably shouldn't be used publicly. // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction. case 'pre': { const base = Number(identifierBase) ? 1 : 0; if (this.prerelease.length === 0) { this.prerelease = [base]; } else { let i = this.prerelease.length; while (--i >= 0) { if (typeof this.prerelease[i] === 'number') { this.prerelease[i]++; i = -2; } } if (i === -1) { // didn't increment anything if (identifier === this.prerelease.join('.') && identifierBase === false) { throw new Error('invalid increment argument: identifier already exists') } this.prerelease.push(base); } } if (identifier) { // 1.2.0-beta.1 bumps to 1.2.0-beta.2, // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 let prerelease = [identifier, base]; if (identifierBase === false) { prerelease = [identifier]; } if (isPrereleaseIdentifier(this.prerelease, identifier)) { const prereleaseBase = this.prerelease[identifier.split('.').length]; if (isNaN(prereleaseBase)) { this.prerelease = prerelease; } } else { this.prerelease = prerelease; } } break } default: throw new Error(`invalid increment argument: ${release}`) } this.raw = this.format(); if (this.build.length) { this.raw += `+${this.build.join('.')}`; } return this } } semver$1 = SemVer; return semver$1; } var parse_1; var hasRequiredParse; function requireParse () { if (hasRequiredParse) return parse_1; hasRequiredParse = 1; const SemVer = requireSemver$1(); const parse = (version, options, throwErrors = false) => { if (version instanceof SemVer) { return version } try { return new SemVer(version, options) } catch (er) { if (!throwErrors) { return null } throw er } }; parse_1 = parse; return parse_1; } var valid_1; var hasRequiredValid$1; function requireValid$1 () { if (hasRequiredValid$1) return valid_1; hasRequiredValid$1 = 1; const parse = requireParse(); const valid = (version, options) => { const v = parse(version, options); return v ? v.version : null }; valid_1 = valid; return valid_1; } var clean_1; var hasRequiredClean; function requireClean () { if (hasRequiredClean) return clean_1; hasRequiredClean = 1; const parse = requireParse(); const clean = (version, options) => { const s = parse(version.trim().replace(/^[=v]+/, ''), options); return s ? s.version : null }; clean_1 = clean; return clean_1; } var inc_1; var hasRequiredInc; function requireInc () { if (hasRequiredInc) return inc_1; hasRequiredInc = 1; const SemVer = requireSemver$1(); const inc = (version, release, options, identifier, identifierBase) => { if (typeof (options) === 'string') { identifierBase = identifier; identifier = options; options = undefined; } try { return new SemVer( version instanceof SemVer ? version.version : version, options ).inc(release, identifier, identifierBase).version } catch (er) { return null } }; inc_1 = inc; return inc_1; } var diff_1; var hasRequiredDiff; function requireDiff () { if (hasRequiredDiff) return diff_1; hasRequiredDiff = 1; const parse = requireParse(); const diff = (version1, version2) => { const v1 = parse(version1, null, true); const v2 = parse(version2, null, true); const comparison = v1.compare(v2); if (comparison === 0) { return null } const v1Higher = comparison > 0; const highVersion = v1Higher ? v1 : v2; const lowVersion = v1Higher ? v2 : v1; const highHasPre = !!highVersion.prerelease.length; const lowHasPre = !!lowVersion.prerelease.length; if (lowHasPre && !highHasPre) { // Going from prerelease -> no prerelease requires some special casing // If the low version has only a major, then it will always be a major // Some examples: // 1.0.0-1 -> 1.0.0 // 1.0.0-1 -> 1.1.1 // 1.0.0-1 -> 2.0.0 if (!lowVersion.patch && !lowVersion.minor) { return 'major' } // If the main part has no difference if (lowVersion.compareMain(highVersion) === 0) { if (lowVersion.minor && !lowVersion.patch) { return 'minor' } return 'patch' } } // add the `pre` prefix if we are going to a prerelease version const prefix = highHasPre ? 'pre' : ''; if (v1.major !== v2.major) { return prefix + 'major' } if (v1.minor !== v2.minor) { return prefix + 'minor' } if (v1.patch !== v2.patch) { return prefix + 'patch' } // high and low are prereleases return 'prerelease' }; diff_1 = diff; return diff_1; } var major_1; var hasRequiredMajor; function requireMajor () { if (hasRequiredMajor) return major_1; hasRequiredMajor = 1; const SemVer = requireSemver$1(); const major = (a, loose) => new SemVer(a, loose).major; major_1 = major; return major_1; } var minor_1; var hasRequiredMinor; function requireMinor () { if (hasRequiredMinor) return minor_1; hasRequiredMinor = 1; const SemVer = requireSemver$1(); const minor = (a, loose) => new SemVer(a, loose).minor; minor_1 = minor; return minor_1; } var patch_1; var hasRequiredPatch; function requirePatch () { if (hasRequiredPatch) return patch_1; hasRequiredPatch = 1; const SemVer = requireSemver$1(); const patch = (a, loose) => new SemVer(a, loose).patch; patch_1 = patch; return patch_1; } var prerelease_1; var hasRequiredPrerelease; function requirePrerelease () { if (hasRequiredPrerelease) return prerelease_1; hasRequiredPrerelease = 1; const parse = requireParse(); const prerelease = (version, options) => { const parsed = parse(version, options); return (parsed && parsed.prerelease.length) ? parsed.prerelease : null }; prerelease_1 = prerelease; return prerelease_1; } var compare_1; var hasRequiredCompare; function requireCompare () { if (hasRequiredCompare) return compare_1; hasRequiredCompare = 1; const SemVer = requireSemver$1(); const compare = (a, b, loose) => new SemVer(a, loose).compare(new SemVer(b, loose)); compare_1 = compare; return compare_1; } var rcompare_1; var hasRequiredRcompare; function requireRcompare () { if (hasRequiredRcompare) return rcompare_1; hasRequiredRcompare = 1; const compare = requireCompare(); const rcompare = (a, b, loose) => compare(b, a, loose); rcompare_1 = rcompare; return rcompare_1; } var compareLoose_1; var hasRequiredCompareLoose; function requireCompareLoose () { if (hasRequiredCompareLoose) return compareLoose_1; hasRequiredCompareLoose = 1; const compare = requireCompare(); const compareLoose = (a, b) => compare(a, b, true); compareLoose_1 = compareLoose; return compareLoose_1; } var compareBuild_1; var hasRequiredCompareBuild; function requireCompareBuild () { if (hasRequiredCompareBuild) return compareBuild_1; hasRequiredCompareBuild = 1; const SemVer = requireSemver$1(); const compareBuild = (a, b, loose) => { const versionA = new SemVer(a, loose); const versionB = new SemVer(b, loose); return versionA.compare(versionB) || versionA.compareBuild(versionB) }; compareBuild_1 = compareBuild; return compareBuild_1; } var sort_1; var hasRequiredSort; function requireSort () { if (hasRequiredSort) return sort_1; hasRequiredSort = 1; const compareBuild = requireCompareBuild(); const sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose)); sort_1 = sort; return sort_1; } var rsort_1; var hasRequiredRsort; function requireRsort () { if (hasRequiredRsort) return rsort_1; hasRequiredRsort = 1; const compareBuild = requireCompareBuild(); const rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose)); rsort_1 = rsort; return rsort_1; } var gt_1; var hasRequiredGt; function requireGt () { if (hasRequiredGt) return gt_1; hasRequiredGt = 1; const compare = requireCompare(); const gt = (a, b, loose) => compare(a, b, loose) > 0; gt_1 = gt; return gt_1; } var lt_1; var hasRequiredLt; function requireLt () { if (hasRequiredLt) return lt_1; hasRequiredLt = 1; const compare = requireCompare(); const lt = (a, b, loose) => compare(a, b, loose) < 0; lt_1 = lt; return lt_1; } var eq_1; var hasRequiredEq; function requireEq () { if (hasRequiredEq) return eq_1; hasRequiredEq = 1; const compare = requireCompare(); const eq = (a, b, loose) => compare(a, b, loose) === 0; eq_1 = eq; return eq_1; } var neq_1; var hasRequiredNeq; function requireNeq () { if (hasRequiredNeq) return neq_1; hasRequiredNeq = 1; const compare = requireCompare(); const neq = (a, b, loose) => compare(a, b, loose) !== 0; neq_1 = neq; return neq_1; } var gte_1; var hasRequiredGte; function requireGte () { if (hasRequiredGte) return gte_1; hasRequiredGte = 1; const compare = requireCompare(); const gte = (a, b, loose) => compare(a, b, loose) >= 0; gte_1 = gte; return gte_1; } var lte_1; var hasRequiredLte; function requireLte () { if (hasRequiredLte) return lte_1; hasRequiredLte = 1; const compare = requireCompare(); const lte = (a, b, loose) => compare(a, b, loose) <= 0; lte_1 = lte; return lte_1; } var cmp_1; var hasRequiredCmp; function requireCmp () { if (hasRequiredCmp) return cmp_1; hasRequiredCmp = 1; const eq = requireEq(); const neq = requireNeq(); const gt = requireGt(); const gte = requireGte(); const lt = requireLt(); const lte = requireLte(); const cmp = (a, op, b, loose) => { switch (op) { case '===': if (typeof a === 'object') { a = a.version; } if (typeof b === 'object') { b = b.version; } return a === b case '!==': if (typeof a === 'object') { a = a.version; } if (typeof b === 'object') { b = b.version; } return a !== b case '': case '=': case '==': return eq(a, b, loose) case '!=': return neq(a, b, loose) case '>': return gt(a, b, loose) case '>=': return gte(a, b, loose) case '<': return lt(a, b, loose) case '<=': return lte(a, b, loose) default: throw new TypeError(`Invalid operator: ${op}`) } }; cmp_1 = cmp; return cmp_1; } var coerce_1; var hasRequiredCoerce; function requireCoerce () { if (hasRequiredCoerce) return coerce_1; hasRequiredCoerce = 1; const SemVer = requireSemver$1(); const parse = requireParse(); const { safeRe: re, t } = requireRe(); const coerce = (version, options) => { if (version instanceof SemVer) { return version } if (typeof version === 'number') { version = String(version); } if (typeof version !== 'string') { return null } options = options || {}; let match = null; if (!options.rtl) { match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE]); } else { // Find the right-most coercible string that does not share // a terminus with a more left-ward coercible string. // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4' // // Walk through the string checking with a /g regexp // Manually set the index so as to pick up overlapping matches. // Stop when we get a match that ends at the string end, since no // coercible string can be more right-ward without the same terminus. const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL]; let next; while ((next = coerceRtlRegex.exec(version)) && (!match || match.index + match[0].length !== version.length) ) { if (!match || next.index + next[0].length !== match.index + match[0].length) { match = next; } coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length; } // leave it in a clean state coerceRtlRegex.lastIndex = -1; } if (match === null) { return null } const major = match[2]; const minor = match[3] || '0'; const patch = match[4] || '0'; const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : ''; const build = options.includePrerelease && match[6] ? `+${match[6]}` : ''; return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options) }; coerce_1 = coerce; return coerce_1; } var truncate_1; var hasRequiredTruncate; function requireTruncate () { if (hasRequiredTruncate) return truncate_1; hasRequiredTruncate = 1; const parse = requireParse(); const constants = requireConstants(); const SemVer = requireSemver$1(); const truncate = (version, truncation, options) => { if (!constants.RELEASE_TYPES.includes(truncation)) { return null } const clonedVersion = cloneInputVersion(version, options); return clonedVersion && doTruncation(clonedVersion, truncation) }; const cloneInputVersion = (version, options) => { const versionStringToParse = ( version instanceof SemVer ? version.version : version ); return parse(versionStringToParse, options) }; const doTruncation = (version, truncation) => { if (isPrerelease(truncation)) { return version.version } version.prerelease = []; switch (truncation) { case 'major': version.minor = 0; version.patch = 0; break case 'minor': version.patch = 0; break } return version.format() }; const isPrerelease = (type) => { return type.startsWith('pre') }; truncate_1 = truncate; return truncate_1; } var lrucache; var hasRequiredLrucache; function requireLrucache () { if (hasRequiredLrucache) return lrucache; hasRequiredLrucache = 1; class LRUCache { constructor () { this.max = 1000; this.map = new Map(); } get (key) { const value = this.map.get(key); if (value === undefined) { return undefined } else { // Remove the key from the map and add it to the end this.map.delete(key); this.map.set(key, value); return value } } delete (key) { return this.map.delete(key) } set (key, value) { const deleted = this.delete(key); if (!deleted && value !== undefined) { // If cache is full, delete the least recently used item if (this.map.size >= this.max) { const firstKey = this.map.keys().next().value; this.delete(firstKey); } this.map.set(key, value); } return this } } lrucache = LRUCache; return lrucache; } var range$1; var hasRequiredRange; function requireRange () { if (hasRequiredRange) return range$1; hasRequiredRange = 1; const SPACE_CHARACTERS = /\s+/g; // hoisted class for cyclic dependency class Range { constructor (range, options) { options = parseOptions(options); if (range instanceof Range) { if ( range.loose === !!options.loose && range.includePrerelease === !!options.includePrerelease ) { return range } else { return new Range(range.raw, options) } } if (range instanceof Comparator) { // just put it in the set and return this.raw = range.value; this.set = [[range]]; this.formatted = undefined; return this } this.options = options; this.loose = !!options.loose; this.includePrerelease = !!options.includePrerelease; // First reduce all whitespace as much as possible so we do not have to rely // on potentially slow regexes like \s*. This is then stored and used for // future error messages as well. this.raw = range.trim().replace(SPACE_CHARACTERS, ' '); // First, split on || this.set = this.raw .split('||') // map the range to a 2d array of comparators .map(r => this.parseRange(r.trim())) // throw out any comparator lists that are empty // this generally means that it was not a valid range, which is allowed // in loose mode, but will still throw if the WHOLE range is invalid. .filter(c => c.length); if (!this.set.length) { throw new TypeError(`Invalid SemVer Range: ${this.raw}`) } // if we have any that are not the null set, throw out null sets. if (this.set.length > 1) { // keep the first one, in case they're all null sets const first = this.set[0]; this.set = this.set.filter(c => !isNullSet(c[0])); if (this.set.length === 0) { this.set = [first]; } else if (this.set.length > 1) { // if we have any that are *, then the range is just * for (const c of this.set) { if (c.length === 1 && isAny(c[0])) { this.set = [c]; break } } } } this.formatted = undefined; } get range () { if (this.formatted === undefined) { this.formatted = ''; for (let i = 0; i < this.set.length; i++) { if (i > 0) { this.formatted += '||'; } const comps = this.set[i]; for (let k = 0; k < comps.length; k++) { if (k > 0) { this.formatted += ' '; } this.formatted += comps[k].toString().trim(); } } } return this.formatted } format () { return this.range } toString () { return this.range } parseRange (range) { // strip build metadata so it can't bleed into the version range = range.replace(BUILDSTRIPRE, ''); // memoize range parsing for performance. // this is a very hot path, and fully deterministic. const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE); const memoKey = memoOpts + ':' + range; const cached = cache.get(memoKey); if (cached) { return cached } const loose = this.options.loose; // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]; range = range.replace(hr, hyphenReplace(this.options.includePrerelease)); debug('hyphen replace', range); // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace); debug('comparator trim', range); // `~ 1.2.3` => `~1.2.3` range = range.replace(re[t.TILDETRIM], tildeTrimReplace); debug('tilde trim', range); // `^ 1.2.3` => `^1.2.3` range = range.replace(re[t.CARETTRIM], caretTrimReplace); debug('caret trim', range); // At this point, the range is completely trimmed and // ready to be split into comparators. let rangeList = range .split(' ') .map(comp => parseComparator(comp, this.options)) .join(' ') .split(/\s+/) // >=0.0.0 is equivalent to * .map(comp => replaceGTE0(comp, this.options)); if (loose) { // in loose mode, throw out any that are not valid comparators rangeList = rangeList.filter(comp => { debug('loose invalid filter', comp, this.options); return !!comp.match(re[t.COMPARATORLOOSE]) }); } debug('range list', rangeList); // if any comparators are the null set, then replace with JUST null set // if more than one comparator, remove any * comparators // also, don't include the same comparator more than once const rangeMap = new Map(); const comparators = rangeList.map(comp => new Comparator(comp, this.options)); for (const comp of comparators) { if (isNullSet(comp)) { return [comp] } rangeMap.set(comp.value, comp); } if (rangeMap.size > 1 && rangeMap.has('')) { rangeMap.delete(''); } const result = [...rangeMap.values()]; cache.set(memoKey, result); return result } intersects (range, options) { if (!(range instanceof Range)) { throw new TypeError('a Range is required') } return this.set.some((thisComparators) => { return ( isSatisfiable(thisComparators, options) && range.set.some((rangeComparators) => { return ( isSatisfiable(rangeComparators, options) && thisComparators.every((thisComparator) => { return rangeComparators.every((rangeComparator) => { return thisComparator.intersects(rangeComparator, options) }) }) ) }) ) }) } // if ANY of the sets match ALL of its comparators, then pass test (version) { if (!version) { return false } if (typeof version === 'string') { try { version = new SemVer(version, this.options); } catch (er) { return false } } for (let i = 0; i < this.set.length; i++) { if (testSet(this.set[i], version, this.options)) { return true } } return false } } range$1 = Range; const LRU = requireLrucache(); const cache = new LRU(); const parseOptions = requireParseOptions(); const Comparator = requireComparator(); const debug = requireDebug(); const SemVer = requireSemver$1(); const { safeRe: re, src, t, comparatorTrimReplace, tildeTrimReplace, caretTrimReplace, } = requireRe(); const { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = requireConstants(); // unbounded global build-metadata stripper used by parseRange const BUILDSTRIPRE = new RegExp(src[t.BUILD], 'g'); const isNullSet = c => c.value === '<0.0.0-0'; const isAny = c => c.value === ''; // take a set of comparators and determine whether there // exists a version which can satisfy it const isSatisfiable = (comparators, options) => { let result = true; const remainingComparators = comparators.slice(); let testComparator = remainingComparators.pop(); while (result && remainingComparators.length) { result = remainingComparators.every((otherComparator) => { return testComparator.intersects(otherComparator, options) }); testComparator = remainingComparators.pop(); } return result }; // comprised of xranges, tildes, stars, and gtlt's at this point. // already replaced the hyphen ranges // turn into a set of JUST comparators. const parseComparator = (comp, options) => { comp = comp.replace(re[t.BUILD], ''); debug('comp', comp, options); comp = replaceCarets(comp, options); debug('caret', comp); comp = replaceTildes(comp, options); debug('tildes', comp); comp = replaceXRanges(comp, options); debug('xrange', comp); comp = replaceStars(comp, options); debug('stars', comp); return comp }; const isX = id => !id || id.toLowerCase() === 'x' || id === '*'; // ~, ~> --> * (any, kinda silly) // ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0 // ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0 // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0 // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0 // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0 // ~0.0.1 --> >=0.0.1 <0.1.0-0 const replaceTildes = (comp, options) => { return comp .trim() .split(/\s+/) .map((c) => replaceTilde(c, options)) .join(' ') }; const replaceTilde = (comp, options) => { const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]; return comp.replace(r, (_, M, m, p, pr) => { debug('tilde', comp, _, M, m, p, pr); let ret; if (isX(M)) { ret = ''; } else if (isX(m)) { ret = `>=${M}.0.0 <${+M + 1}.0.0-0`; } else if (isX(p)) { // ~1.2 == >=1.2.0 <1.3.0-0 ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`; } else if (pr) { debug('replaceTilde pr', pr); ret = `>=${M}.${m}.${p}-${pr } <${M}.${+m + 1}.0-0`; } else { // ~1.2.3 == >=1.2.3 <1.3.0-0 ret = `>=${M}.${m}.${p } <${M}.${+m + 1}.0-0`; } debug('tilde return', ret); return ret }) }; // ^ --> * (any, kinda silly) // ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0-0 // ^2.0, ^2.0.x --> >=2.0.0 <3.0.0-0 // ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0 // ^1.2.3 --> >=1.2.3 <2.0.0-0 // ^1.2.0 --> >=1.2.0 <2.0.0-0 // ^0.0.1 --> >=0.0.1 <0.0.2-0 // ^0.1.0 --> >=0.1.0 <0.2.0-0 const replaceCarets = (comp, options) => { return comp .trim() .split(/\s+/) .map((c) => replaceCaret(c, options)) .join(' ') }; const replaceCaret = (comp, options) => { debug('caret', comp, options); const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]; const z = options.includePrerelease ? '-0' : ''; return comp.replace(r, (_, M, m, p, pr) => { debug('caret', comp, _, M, m, p, pr); let ret; if (isX(M)) { ret = ''; } else if (isX(m)) { ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`; } else if (isX(p)) { if (M === '0') { ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`; } else { ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`; } } else if (pr) { debug('replaceCaret pr', pr); if (M === '0') { if (m === '0') { ret = `>=${M}.${m}.${p}-${pr } <${M}.${m}.${+p + 1}-0`; } else { ret = `>=${M}.${m}.${p}-${pr } <${M}.${+m + 1}.0-0`; } } else { ret = `>=${M}.${m}.${p}-${pr } <${+M + 1}.0.0-0`; } } else { debug('no pr'); if (M === '0') { if (m === '0') { ret = `>=${M}.${m}.${p }${z} <${M}.${m}.${+p + 1}-0`; } else { ret = `>=${M}.${m}.${p }${z} <${M}.${+m + 1}.0-0`; } } else { ret = `>=${M}.${m}.${p } <${+M + 1}.0.0-0`; } } debug('caret return', ret); return ret }) }; const replaceXRanges = (comp, options) => { debug('replaceXRanges', comp, options); return comp .split(/\s+/) .map((c) => replaceXRange(c, options)) .join(' ') }; const replaceXRange = (comp, options) => { comp = comp.trim(); const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]; return comp.replace(r, (ret, gtlt, M, m, p, pr) => { debug('xRange', comp, ret, gtlt, M, m, p, pr); const xM = isX(M); const xm = xM || isX(m); const xp = xm || isX(p); const anyX = xp; if (gtlt === '=' && anyX) { gtlt = ''; } // if we're including prereleases in the match, then we need // to fix this to -0, the lowest possible prerelease value pr = options.includePrerelease ? '-0' : ''; if (xM) { if (gtlt === '>' || gtlt === '<') { // nothing is allowed ret = '<0.0.0-0'; } else { // nothing is forbidden ret = '*'; } } else if (gtlt && anyX) { // we know patch is an x, because we have any x at all. // replace X with 0 if (xm) { m = 0; } p = 0; if (gtlt === '>') { // >1 => >=2.0.0 // >1.2 => >=1.3.0 gtlt = '>='; if (xm) { M = +M + 1; m = 0; p = 0; } else { m = +m + 1; p = 0; } } else if (gtlt === '<=') { // <=0.7.x is actually <0.8.0, since any 0.7.x should // pass. Similarly, <=7.x is actually <8.0.0, etc. gtlt = '<'; if (xm) { M = +M + 1; } else { m = +m + 1; } } if (gtlt === '<') { pr = '-0'; } ret = `${gtlt + M}.${m}.${p}${pr}`; } else if (xm) { ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`; } else if (xp) { ret = `>=${M}.${m}.0${pr } <${M}.${+m + 1}.0-0`; } debug('xRange return', ret); return ret }) }; // Because * is AND-ed with everything else in the comparator, // and '' means "any version", just remove the *s entirely. const replaceStars = (comp, options) => { debug('replaceStars', comp, options); // Looseness is ignored here. star is always as loose as it gets! return comp .trim() .replace(re[t.STAR], '') }; const replaceGTE0 = (comp, options) => { debug('replaceGTE0', comp, options); return comp .trim() .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '') }; // This function is passed to string.replace(re[t.HYPHENRANGE]) // M, m, patch, prerelease, build // 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 // 1.2.3 - 3.4 => >=1.2.0 <3.5.0-0 Any 3.4.x will do // 1.2 - 3.4 => >=1.2.0 <3.5.0-0 // TODO build? const hyphenReplace = incPr => ($0, from, fM, fm, fp, fpr, fb, to, tM, tm, tp, tpr) => { if (isX(fM)) { from = ''; } else if (isX(fm)) { from = `>=${fM}.0.0${incPr ? '-0' : ''}`; } else if (isX(fp)) { from = `>=${fM}.${fm}.0${incPr ? '-0' : ''}`; } else if (fpr) { from = `>=${from}`; } else { from = `>=${from}${incPr ? '-0' : ''}`; } if (isX(tM)) { to = ''; } else if (isX(tm)) { to = `<${+tM + 1}.0.0-0`; } else if (isX(tp)) { to = `<${tM}.${+tm + 1}.0-0`; } else if (tpr) { to = `<=${tM}.${tm}.${tp}-${tpr}`; } else if (incPr) { to = `<${tM}.${tm}.${+tp + 1}-0`; } else { to = `<=${to}`; } return `${from} ${to}`.trim() }; const testSet = (set, version, options) => { for (let i = 0; i < set.length; i++) { if (!set[i].test(version)) { return false } } if (version.prerelease.length && !options.includePrerelease) { // Find the set of versions that are allowed to have prereleases // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 // That should allow `1.2.3-pr.2` to pass. // However, `1.2.4-alpha.notready` should NOT be allowed, // even though it's within the range set by the comparators. for (let i = 0; i < set.length; i++) { debug(set[i].semver); if (set[i].semver === Comparator.ANY) { continue } if (set[i].semver.prerelease.length > 0) { const allowed = set[i].semver; if (allowed.major === version.major && allowed.minor === version.minor && allowed.patch === version.patch) { return true } } } // Version has a -pre, but it's not one of the ones we like. return false } return true }; return range$1; } var comparator; var hasRequiredComparator; function requireComparator () { if (hasRequiredComparator) return comparator; hasRequiredComparator = 1; const ANY = Symbol('SemVer ANY'); // hoisted class for cyclic dependency class Comparator { static get ANY () { return ANY } constructor (comp, options) { options = parseOptions(options); if (comp instanceof Comparator) { if (comp.loose === !!options.loose) { return comp } else { comp = comp.value; } } comp = comp.trim().split(/\s+/).join(' '); debug('comparator', comp, options); this.options = options; this.loose = !!options.loose; this.parse(comp); if (this.semver === ANY) { this.value = ''; } else { this.value = this.operator + this.semver.version; } debug('comp', this); } parse (comp) { const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]; const m = comp.match(r); if (!m) { throw new TypeError(`Invalid comparator: ${comp}`) } this.operator = m[1] !== undefined ? m[1] : ''; if (this.operator === '=') { this.operator = ''; } // if it literally is just '>' or '' then allow anything. if (!m[2]) { this.semver = ANY; } else { this.semver = new SemVer(m[2], this.options.loose); } } toString () { return this.value } test (version) { debug('Comparator.test', version, this.options.loose); if (this.semver === ANY || version === ANY) { return true } if (typeof version === 'string') { try { version = new SemVer(version, this.options); } catch (er) { return false } } return cmp(version, this.operator, this.semver, this.options) } intersects (comp, options) { if (!(comp instanceof Comparator)) { throw new TypeError('a Comparator is required') } if (this.operator === '') { if (this.value === '') { return true } return new Range(comp.value, options).test(this.value) } else if (comp.operator === '') { if (comp.value === '') { return true } return new Range(this.value, options).test(comp.semver) } options = parseOptions(options); // Special cases where nothing can possibly be lower if (options.includePrerelease && (this.value === '<0.0.0-0' || comp.value === '<0.0.0-0')) { return false } if (!options.includePrerelease && (this.value.startsWith('<0.0.0') || comp.value.startsWith('<0.0.0'))) { return false } // Same direction increasing (> or >=) if (this.operator.startsWith('>') && comp.operator.startsWith('>')) { return true } // Same direction decreasing (< or <=) if (this.operator.startsWith('<') && comp.operator.startsWith('<')) { return true } // same SemVer and both sides are inclusive (<= or >=) if ( (this.semver.version === comp.semver.version) && this.operator.includes('=') && comp.operator.includes('=')) { return true } // opposite directions less than if (cmp(this.semver, '<', comp.semver, options) && this.operator.startsWith('>') && comp.operator.startsWith('<')) { return true } // opposite directions greater than if (cmp(this.semver, '>', comp.semver, options) && this.operator.startsWith('<') && comp.operator.startsWith('>')) { return true } return false } } comparator = Comparator; const parseOptions = requireParseOptions(); const { safeRe: re, t } = requireRe(); const cmp = requireCmp(); const debug = requireDebug(); const SemVer = requireSemver$1(); const Range = requireRange(); return comparator; } var satisfies_1; var hasRequiredSatisfies; function requireSatisfies () { if (hasRequiredSatisfies) return satisfies_1; hasRequiredSatisfies = 1; const Range = requireRange(); const satisfies = (version, range, options) => { try { range = new Range(range, options); } catch (er) { return false } return range.test(version) }; satisfies_1 = satisfies; return satisfies_1; } var toComparators_1; var hasRequiredToComparators; function requireToComparators () { if (hasRequiredToComparators) return toComparators_1; hasRequiredToComparators = 1; const Range = requireRange(); // Mostly just for testing and legacy API reasons const toComparators = (range, options) => new Range(range, options).set .map(comp => comp.map(c => c.value).join(' ').trim().split(' ')); toComparators_1 = toComparators; return toComparators_1; } var maxSatisfying_1; var hasRequiredMaxSatisfying; function requireMaxSatisfying () { if (hasRequiredMaxSatisfying) return maxSatisfying_1; hasRequiredMaxSatisfying = 1; const SemVer = requireSemver$1(); const Range = requireRange(); const maxSatisfying = (versions, range, options) => { let max = null; let maxSV = null; let rangeObj = null; try { rangeObj = new Range(range, options); } catch (er) { return null } versions.forEach((v) => { if (rangeObj.test(v)) { // satisfies(v, range, options) if (!max || maxSV.compare(v) === -1) { // compare(max, v, true) max = v; maxSV = new SemVer(max, options); } } }); return max }; maxSatisfying_1 = maxSatisfying; return maxSatisfying_1; } var minSatisfying_1; var hasRequiredMinSatisfying; function requireMinSatisfying () { if (hasRequiredMinSatisfying) return minSatisfying_1; hasRequiredMinSatisfying = 1; const SemVer = requireSemver$1(); const Range = requireRange(); const minSatisfying = (versions, range, options) => { let min = null; let minSV = null; let rangeObj = null; try { rangeObj = new Range(range, options); } catch (er) { return null } versions.forEach((v) => { if (rangeObj.test(v)) { // satisfies(v, range, options) if (!min || minSV.compare(v) === 1) { // compare(min, v, true) min = v; minSV = new SemVer(min, options); } } }); return min }; minSatisfying_1 = minSatisfying; return minSatisfying_1; } var minVersion_1; var hasRequiredMinVersion; function requireMinVersion () { if (hasRequiredMinVersion) return minVersion_1; hasRequiredMinVersion = 1; const SemVer = requireSemver$1(); const Range = requireRange(); const gt = requireGt(); const minVersion = (range, loose) => { range = new Range(range, loose); let minver = new SemVer('0.0.0'); if (range.test(minver)) { return minver } minver = new SemVer('0.0.0-0'); if (range.test(minver)) { return minver } minver = null; for (let i = 0; i < range.set.length; ++i) { const comparators = range.set[i]; let setMin = null; comparators.forEach((comparator) => { // Clone to avoid manipulating the comparator's semver object. const compver = new SemVer(comparator.semver.version); switch (comparator.operator) { case '>': if (compver.prerelease.length === 0) { compver.patch++; } else { compver.prerelease.push(0); } compver.raw = compver.format(); /* fallthrough */ case '': case '>=': if (!setMin || gt(compver, setMin)) { setMin = compver; } break case '<': case '<=': /* Ignore maximum versions */ break /* istanbul ignore next */ default: throw new Error(`Unexpected operation: ${comparator.operator}`) } }); if (setMin && (!minver || gt(minver, setMin))) { minver = setMin; } } if (minver && range.test(minver)) { return minver } return null }; minVersion_1 = minVersion; return minVersion_1; } var valid; var hasRequiredValid; function requireValid () { if (hasRequiredValid) return valid; hasRequiredValid = 1; const Range = requireRange(); const validRange = (range, options) => { try { // Return '*' instead of '' so that truthiness works. // This will throw if it's invalid anyway return new Range(range, options).range || '*' } catch (er) { return null } }; valid = validRange; return valid; } var outside_1; var hasRequiredOutside; function requireOutside () { if (hasRequiredOutside) return outside_1; hasRequiredOutside = 1; const SemVer = requireSemver$1(); const Comparator = requireComparator(); const { ANY } = Comparator; const Range = requireRange(); const satisfies = requireSatisfies(); const gt = requireGt(); const lt = requireLt(); const lte = requireLte(); const gte = requireGte(); const outside = (version, range, hilo, options) => { version = new SemVer(version, options); range = new Range(range, options); let gtfn, ltefn, ltfn, comp, ecomp; switch (hilo) { case '>': gtfn = gt; ltefn = lte; ltfn = lt; comp = '>'; ecomp = '>='; break case '<': gtfn = lt; ltefn = gte; ltfn = gt; comp = '<'; ecomp = '<='; break default: throw new TypeError('Must provide a hilo val of "<" or ">"') } // If it satisfies the range it is not outside if (satisfies(version, range, options)) { return false } // From now on, variable terms are as if we're in "gtr" mode. // but note that everything is flipped for the "ltr" function. for (let i = 0; i < range.set.length; ++i) { const comparators = range.set[i]; let high = null; let low = null; comparators.forEach((comparator) => { if (comparator.semver === ANY) { comparator = new Comparator('>=0.0.0'); } high = high || comparator; low = low || comparator; if (gtfn(comparator.semver, high.semver, options)) { high = comparator; } else if (ltfn(comparator.semver, low.semver, options)) { low = comparator; } }); // If the edge version comparator has a operator then our version // isn't outside it if (high.operator === comp || high.operator === ecomp) { return false } // If the lowest version comparator has an operator and our version // is less than it then it isn't higher than the range if ((!low.operator || low.operator === comp) && ltefn(version, low.semver)) { return false } else if (low.operator === ecomp && ltfn(version, low.semver)) { return false } } return true }; outside_1 = outside; return outside_1; } var gtr_1; var hasRequiredGtr; function requireGtr () { if (hasRequiredGtr) return gtr_1; hasRequiredGtr = 1; // Determine if version is greater than all the versions possible in the range. const outside = requireOutside(); const gtr = (version, range, options) => outside(version, range, '>', options); gtr_1 = gtr; return gtr_1; } var ltr_1; var hasRequiredLtr; function requireLtr () { if (hasRequiredLtr) return ltr_1; hasRequiredLtr = 1; const outside = requireOutside(); // Determine if version is less than all the versions possible in the range const ltr = (version, range, options) => outside(version, range, '<', options); ltr_1 = ltr; return ltr_1; } var intersects_1; var hasRequiredIntersects; function requireIntersects () { if (hasRequiredIntersects) return intersects_1; hasRequiredIntersects = 1; const Range = requireRange(); const intersects = (r1, r2, options) => { r1 = new Range(r1, options); r2 = new Range(r2, options); return r1.intersects(r2, options) }; intersects_1 = intersects; return intersects_1; } var simplify; var hasRequiredSimplify; function requireSimplify () { if (hasRequiredSimplify) return simplify; hasRequiredSimplify = 1; // given a set of versions and a range, create a "simplified" range // that includes the same versions that the original range does // If the original range is shorter than the simplified one, return that. const satisfies = requireSatisfies(); const compare = requireCompare(); simplify = (versions, range, options) => { const set = []; let first = null; let prev = null; const v = versions.sort((a, b) => compare(a, b, options)); for (const version of v) { const included = satisfies(version, range, options); if (included) { prev = version; if (!first) { first = version; } } else { if (prev) { set.push([first, prev]); } prev = null; first = null; } } if (first) { set.push([first, null]); } const ranges = []; for (const [min, max] of set) { if (min === max) { ranges.push(min); } else if (!max && min === v[0]) { ranges.push('*'); } else if (!max) { ranges.push(`>=${min}`); } else if (min === v[0]) { ranges.push(`<=${max}`); } else { ranges.push(`${min} - ${max}`); } } const simplified = ranges.join(' || '); const original = typeof range.raw === 'string' ? range.raw : String(range); return simplified.length < original.length ? simplified : range }; return simplify; } var subset_1; var hasRequiredSubset; function requireSubset () { if (hasRequiredSubset) return subset_1; hasRequiredSubset = 1; const Range = requireRange(); const Comparator = requireComparator(); const { ANY } = Comparator; const satisfies = requireSatisfies(); const compare = requireCompare(); // Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff: // - Every simple range `r1, r2, ...` is a null set, OR // - Every simple range `r1, r2, ...` which is not a null set is a subset of // some `R1, R2, ...` // // Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff: // - If c is only the ANY comparator // - If C is only the ANY comparator, return true // - Else if in prerelease mode, return false // - else replace c with `[>=0.0.0]` // - If C is only the ANY comparator // - if in prerelease mode, return true // - else replace C with `[>=0.0.0]` // - Let EQ be the set of = comparators in c // - If EQ is more than one, return true (null set) // - Let GT be the highest > or >= comparator in c // - Let LT be the lowest < or <= comparator in c // - If GT and LT, and GT.semver > LT.semver, return true (null set) // - If any C is a = range, and GT or LT are set, return false // - If EQ // - If GT, and EQ does not satisfy GT, return true (null set) // - If LT, and EQ does not satisfy LT, return true (null set) // - If EQ satisfies every C, return true // - Else return false // - If GT // - If GT.semver is lower than any > or >= comp in C, return false // - If GT is >=, and GT.semver does not satisfy every C, return false // - If GT.semver has a prerelease, and not in prerelease mode // - If no C has a prerelease and the GT.semver tuple, return false // - If LT // - If LT.semver is greater than any < or <= comp in C, return false // - If LT is <=, and LT.semver does not satisfy every C, return false // - If LT.semver has a prerelease, and not in prerelease mode // - If no C has a prerelease and the LT.semver tuple, return false // - Else return true const subset = (sub, dom, options = {}) => { if (sub === dom) { return true } sub = new Range(sub, options); dom = new Range(dom, options); let sawNonNull = false; OUTER: for (const simpleSub of sub.set) { for (const simpleDom of dom.set) { const isSub = simpleSubset(simpleSub, simpleDom, options); sawNonNull = sawNonNull || isSub !== null; if (isSub) { continue OUTER } } // the null set is a subset of everything, but null simple ranges in // a complex range should be ignored. so if we saw a non-null range, // then we know this isn't a subset, but if EVERY simple range was null, // then it is a subset. if (sawNonNull) { return false } } return true }; const minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')]; const minimumVersion = [new Comparator('>=0.0.0')]; const simpleSubset = (sub, dom, options) => { if (sub === dom) { return true } if (sub.length === 1 && sub[0].semver === ANY) { if (dom.length === 1 && dom[0].semver === ANY) { return true } else if (options.includePrerelease) { sub = minimumVersionWithPreRelease; } else { sub = minimumVersion; } } if (dom.length === 1 && dom[0].semver === ANY) { if (options.includePrerelease) { return true } else { dom = minimumVersion; } } const eqSet = new Set(); let gt, lt; for (const c of sub) { if (c.operator === '>' || c.operator === '>=') { gt = higherGT(gt, c, options); } else if (c.operator === '<' || c.operator === '<=') { lt = lowerLT(lt, c, options); } else { eqSet.add(c.semver); } } if (eqSet.size > 1) { return null } let gtltComp; if (gt && lt) { gtltComp = compare(gt.semver, lt.semver, options); if (gtltComp > 0) { return null } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) { return null } } // will iterate one or zero times for (const eq of eqSet) { if (gt && !satisfies(eq, String(gt), options)) { return null } if (lt && !satisfies(eq, String(lt), options)) { return null } for (const c of dom) { if (!satisfies(eq, String(c), options)) { return false } } return true } let higher, lower; let hasDomLT, hasDomGT; // if the subset has a prerelease, we need a comparator in the superset // with the same tuple and a prerelease, or it's not a subset let needDomLTPre = lt && !options.includePrerelease && lt.semver.prerelease.length ? lt.semver : false; let needDomGTPre = gt && !options.includePrerelease && gt.semver.prerelease.length ? gt.semver : false; // exception: <1.2.3-0 is the same as <1.2.3 if (needDomLTPre && needDomLTPre.prerelease.length === 1 && lt.operator === '<' && needDomLTPre.prerelease[0] === 0) { needDomLTPre = false; } for (const c of dom) { hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='; hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='; if (gt) { if (needDomGTPre) { if (c.semver.prerelease && c.semver.prerelease.length && c.semver.major === needDomGTPre.major && c.semver.minor === needDomGTPre.minor && c.semver.patch === needDomGTPre.patch) { needDomGTPre = false; } } if (c.operator === '>' || c.operator === '>=') { higher = higherGT(gt, c, options); if (higher === c && higher !== gt) { return false } } else if (gt.operator === '>=' && !c.test(gt.semver)) { return false } } if (lt) { if (needDomLTPre) { if (c.semver.prerelease && c.semver.prerelease.length && c.semver.major === needDomLTPre.major && c.semver.minor === needDomLTPre.minor && c.semver.patch === needDomLTPre.patch) { needDomLTPre = false; } } if (c.operator === '<' || c.operator === '<=') { lower = lowerLT(lt, c, options); if (lower === c && lower !== lt) { return false } } else if (lt.operator === '<=' && !c.test(lt.semver)) { return false } } if (!c.operator && (lt || gt) && gtltComp !== 0) { return false } } // if there was a < or >, and nothing in the dom, then must be false // UNLESS it was limited by another range in the other direction. // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0 if (gt && hasDomLT && !lt && gtltComp !== 0) { return false } if (lt && hasDomGT && !gt && gtltComp !== 0) { return false } // we needed a prerelease range in a specific tuple, but didn't get one // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0, // because it includes prereleases in the 1.2.3 tuple if (needDomGTPre || needDomLTPre) { return false } return true }; // >=1.2.3 is lower than >1.2.3 const higherGT = (a, b, options) => { if (!a) { return b } const comp = compare(a.semver, b.semver, options); return comp > 0 ? a : comp < 0 ? b : b.operator === '>' && a.operator === '>=' ? b : a }; // <=1.2.3 is higher than <1.2.3 const lowerLT = (a, b, options) => { if (!a) { return b } const comp = compare(a.semver, b.semver, options); return comp < 0 ? a : comp > 0 ? b : b.operator === '<' && a.operator === '<=' ? b : a }; subset_1 = subset; return subset_1; } var semver; var hasRequiredSemver; function requireSemver () { if (hasRequiredSemver) return semver; hasRequiredSemver = 1; // just pre-load all the stuff that index.js lazily exports const internalRe = requireRe(); const constants = requireConstants(); const SemVer = requireSemver$1(); const identifiers = requireIdentifiers(); const parse = requireParse(); const valid = requireValid$1(); const clean = requireClean(); const inc = requireInc(); const diff = requireDiff(); const major = requireMajor(); const minor = requireMinor(); const patch = requirePatch(); const prerelease = requirePrerelease(); const compare = requireCompare(); const rcompare = requireRcompare(); const compareLoose = requireCompareLoose(); const compareBuild = requireCompareBuild(); const sort = requireSort(); const rsort = requireRsort(); const gt = requireGt(); const lt = requireLt(); const eq = requireEq(); const neq = requireNeq(); const gte = requireGte(); const lte = requireLte(); const cmp = requireCmp(); const coerce = requireCoerce(); const truncate = requireTruncate(); const Comparator = requireComparator(); const Range = requireRange(); const satisfies = requireSatisfies(); const toComparators = requireToComparators(); const maxSatisfying = requireMaxSatisfying(); const minSatisfying = requireMinSatisfying(); const minVersion = requireMinVersion(); const validRange = requireValid(); const outside = requireOutside(); const gtr = requireGtr(); const ltr = requireLtr(); const intersects = requireIntersects(); const simplifyRange = requireSimplify(); const subset = requireSubset(); semver = { parse, valid, clean, inc, diff, major, minor, patch, prerelease, compare, rcompare, compareLoose, compareBuild, sort, rsort, gt, lt, eq, neq, gte, lte, cmp, coerce, truncate, Comparator, Range, satisfies, toComparators, maxSatisfying, minSatisfying, minVersion, validRange, outside, gtr, ltr, intersects, simplifyRange, subset, SemVer, re: internalRe.re, src: internalRe.src, tokens: internalRe.t, SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION, RELEASE_TYPES: constants.RELEASE_TYPES, compareIdentifiers: identifiers.compareIdentifiers, rcompareIdentifiers: identifiers.rcompareIdentifiers, }; return semver; } var semverExports = requireSemver(); var CacheFilename; (function (CacheFilename) { CacheFilename["Gzip"] = "cache.tgz"; CacheFilename["Zstd"] = "cache.tzst"; })(CacheFilename || (CacheFilename = {})); var CompressionMethod; (function (CompressionMethod) { CompressionMethod["Gzip"] = "gzip"; // Long range mode was added to zstd in v1.3.2. // This enum is for earlier version of zstd that does not have --long support CompressionMethod["ZstdWithoutLong"] = "zstd-without-long"; CompressionMethod["Zstd"] = "zstd"; })(CompressionMethod || (CompressionMethod = {})); var ArchiveToolType; (function (ArchiveToolType) { ArchiveToolType["GNU"] = "gnu"; ArchiveToolType["BSD"] = "bsd"; })(ArchiveToolType || (ArchiveToolType = {})); // The default number of retry attempts. const DefaultRetryAttempts = 2; // The default delay in milliseconds between retry attempts. const DefaultRetryDelay = 5000; // Socket timeout in milliseconds during download. If no traffic is received // over the socket during this period, the socket is destroyed and the download // is aborted. const SocketTimeout = 5000; // The default path of GNUtar on hosted Windows runners const GnuTarPathOnWindows = `${process.env['PROGRAMFILES']}\\Git\\usr\\bin\\tar.exe`; // The default path of BSDtar on hosted Windows runners const SystemTarPathOnWindows = `${process.env['SYSTEMDRIVE']}\\Windows\\System32\\tar.exe`; const TarFilename = 'cache.tar'; const ManifestFilename = 'manifest.txt'; var __awaiter$7 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __asyncValues = (undefined && undefined.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; const versionSalt = '1.0'; // From https://github.com/actions/toolkit/blob/main/packages/tool-cache/src/tool-cache.ts#L23 function createTempDirectory() { return __awaiter$7(this, void 0, void 0, function* () { const IS_WINDOWS = process.platform === 'win32'; let tempDirectory = process.env['RUNNER_TEMP'] || ''; if (!tempDirectory) { let baseLocation; if (IS_WINDOWS) { // On Windows use the USERPROFILE env variable baseLocation = process.env['USERPROFILE'] || 'C:\\'; } else { if (process.platform === 'darwin') { baseLocation = '/Users'; } else { baseLocation = '/home'; } } tempDirectory = path.join(baseLocation, 'actions', 'temp'); } const dest = path.join(tempDirectory, crypto$1.randomUUID()); yield mkdirP(dest); return dest; }); } function getArchiveFileSizeInBytes(filePath) { return fs.statSync(filePath).size; } function resolvePaths(patterns) { return __awaiter$7(this, void 0, void 0, function* () { var _a, e_1, _b, _c; var _d; const paths = []; const workspace = (_d = process.env['GITHUB_WORKSPACE']) !== null && _d !== void 0 ? _d : process.cwd(); const globber = yield create(patterns.join('\n'), { implicitDescendants: false }); try { for (var _e = true, _f = __asyncValues(globber.globGenerator()), _g; _g = yield _f.next(), _a = _g.done, !_a; _e = true) { _c = _g.value; _e = false; const file = _c; const relativeFile = path .relative(workspace, file) .replace(new RegExp(`\\${path.sep}`, 'g'), '/'); debug(`Matched: ${relativeFile}`); // Paths are made relative so the tar entries are all relative to the root of the workspace. if (relativeFile === '') { // path.relative returns empty string if workspace and file are equal paths.push('.'); } else { paths.push(`${relativeFile}`); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_e && !_a && (_b = _f.return)) yield _b.call(_f); } finally { if (e_1) throw e_1.error; } } return paths; }); } function unlinkFile(filePath) { return __awaiter$7(this, void 0, void 0, function* () { return require$$0$1.promisify(fs.unlink)(filePath); }); } function getVersion(app_1) { return __awaiter$7(this, arguments, void 0, function* (app, additionalArgs = []) { let versionOutput = ''; additionalArgs.push('--version'); debug(`Checking ${app} ${additionalArgs.join(' ')}`); try { yield exec(`${app}`, additionalArgs, { ignoreReturnCode: true, silent: true, listeners: { stdout: (data) => (versionOutput += data.toString()), stderr: (data) => (versionOutput += data.toString()) } }); } catch (err) { debug(err.message); } versionOutput = versionOutput.trim(); debug(versionOutput); return versionOutput; }); } // Use zstandard if possible to maximize cache performance function getCompressionMethod() { return __awaiter$7(this, void 0, void 0, function* () { const versionOutput = yield getVersion('zstd', ['--quiet']); const version = semverExports.clean(versionOutput); debug(`zstd version: ${version}`); if (versionOutput === '') { return CompressionMethod.Gzip; } else { return CompressionMethod.ZstdWithoutLong; } }); } function getCacheFileName(compressionMethod) { return compressionMethod === CompressionMethod.Gzip ? CacheFilename.Gzip : CacheFilename.Zstd; } function getGnuTarPathOnWindows() { return __awaiter$7(this, void 0, void 0, function* () { if (fs.existsSync(GnuTarPathOnWindows)) { return GnuTarPathOnWindows; } const versionOutput = yield getVersion('tar'); return versionOutput.toLowerCase().includes('gnu tar') ? which('tar') : ''; }); } function assertDefined(name, value) { if (value === undefined) { throw Error(`Expected ${name} but value was undefiend`); } return value; } function getCacheVersion(paths, compressionMethod, enableCrossOsArchive = false) { // don't pass changes upstream const components = paths.slice(); // Add compression method to cache version to restore // compressed cache as per compression method if (compressionMethod) { components.push(compressionMethod); } // Only check for windows platforms if enableCrossOsArchive is false if (process.platform === 'win32' && !enableCrossOsArchive) { components.push('windows-only'); } // Add salt to cache version to support breaking changes in cache entry components.push(versionSalt); return crypto$1.createHash('sha256').update(components.join('|')).digest('hex'); } function getRuntimeToken() { const token = process.env['ACTIONS_RUNTIME_TOKEN']; if (!token) { throw new Error('Unable to get the ACTIONS_RUNTIME_TOKEN env variable'); } return token; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * This error is thrown when an asynchronous operation has been aborted. * Check for this error by testing the `name` that the name property of the * error matches `"AbortError"`. * * @example * ```ts snippet:ReadmeSampleAbortError * import { AbortError } from "@typespec/ts-http-runtime"; * * async function doAsyncWork(options: { abortSignal: AbortSignal }): Promise { * if (options.abortSignal.aborted) { * throw new AbortError(); * } * * // do async work * } * * const controller = new AbortController(); * controller.abort(); * * try { * doAsyncWork({ abortSignal: controller.signal }); * } catch (e) { * if (e instanceof Error && e.name === "AbortError") { * // handle abort error here. * } * } * ``` */ let AbortError$3 = class AbortError extends Error { constructor(message) { super(message); this.name = "AbortError"; } }; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function log(message, ...args) { process$1.stderr.write(`${require$$1.format(message, ...args)}${EOL$1}`); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Returns the value of the specified environment variable. * * @internal */ function getEnvironmentVariable(name) { return process$1.env[name]; } /** * A constant that indicates whether the environment the code is running is Deno. */ typeof process$1.versions.deno === "string" && process$1.versions.deno.length > 0; /** * A constant that indicates whether the environment the code is running is Bun.sh. */ typeof process$1.versions.bun === "string" && process$1.versions.bun.length > 0; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const debugEnvVariable = getEnvironmentVariable("DEBUG"); let enabledString; let enabledNamespaces = []; let skippedNamespaces = []; const debuggers = []; if (debugEnvVariable) { enable(debugEnvVariable); } const debugObj = Object.assign((namespace) => { return createDebugger(namespace); }, { enable, enabled, disable, log, }); function enable(namespaces) { enabledString = namespaces; enabledNamespaces = []; skippedNamespaces = []; const namespaceList = namespaces.split(",").map((ns) => ns.trim()); for (const ns of namespaceList) { if (ns.startsWith("-")) { skippedNamespaces.push(ns.substring(1)); } else { enabledNamespaces.push(ns); } } for (const instance of debuggers) { instance.enabled = enabled(instance.namespace); } } function enabled(namespace) { if (namespace.endsWith("*")) { return true; } for (const skipped of skippedNamespaces) { if (namespaceMatches(namespace, skipped)) { return false; } } for (const enabledNamespace of enabledNamespaces) { if (namespaceMatches(namespace, enabledNamespace)) { return true; } } return false; } /** * Given a namespace, check if it matches a pattern. * Patterns only have a single wildcard character which is *. * The behavior of * is that it matches zero or more other characters. */ function namespaceMatches(namespace, patternToMatch) { // simple case, no pattern matching required if (patternToMatch.indexOf("*") === -1) { return namespace === patternToMatch; } let pattern = patternToMatch; // normalize successive * if needed if (patternToMatch.indexOf("**") !== -1) { const patternParts = []; let lastCharacter = ""; for (const character of patternToMatch) { if (character === "*" && lastCharacter === "*") { continue; } else { lastCharacter = character; patternParts.push(character); } } pattern = patternParts.join(""); } let namespaceIndex = 0; let patternIndex = 0; const patternLength = pattern.length; const namespaceLength = namespace.length; let lastWildcard = -1; let lastWildcardNamespace = -1; while (namespaceIndex < namespaceLength && patternIndex < patternLength) { if (pattern[patternIndex] === "*") { lastWildcard = patternIndex; patternIndex++; if (patternIndex === patternLength) { // if wildcard is the last character, it will match the remaining namespace string return true; } // now we let the wildcard eat characters until we match the next literal in the pattern while (namespace[namespaceIndex] !== pattern[patternIndex]) { namespaceIndex++; // reached the end of the namespace without a match if (namespaceIndex === namespaceLength) { return false; } } // now that we have a match, let's try to continue on // however, it's possible we could find a later match // so keep a reference in case we have to backtrack lastWildcardNamespace = namespaceIndex; namespaceIndex++; patternIndex++; continue; } else if (pattern[patternIndex] === namespace[namespaceIndex]) { // simple case: literal pattern matches so keep going patternIndex++; namespaceIndex++; } else if (lastWildcard >= 0) { // special case: we don't have a literal match, but there is a previous wildcard // which we can backtrack to and try having the wildcard eat the match instead patternIndex = lastWildcard + 1; namespaceIndex = lastWildcardNamespace + 1; // we've reached the end of the namespace without a match if (namespaceIndex === namespaceLength) { return false; } // similar to the previous logic, let's keep going until we find the next literal match while (namespace[namespaceIndex] !== pattern[patternIndex]) { namespaceIndex++; if (namespaceIndex === namespaceLength) { return false; } } lastWildcardNamespace = namespaceIndex; namespaceIndex++; patternIndex++; continue; } else { return false; } } const namespaceDone = namespaceIndex === namespace.length; const patternDone = patternIndex === pattern.length; // this is to detect the case of an unneeded final wildcard // e.g. the pattern `ab*` should match the string `ab` const trailingWildCard = patternIndex === pattern.length - 1 && pattern[patternIndex] === "*"; return namespaceDone && (patternDone || trailingWildCard); } function disable() { const result = enabledString || ""; enable(""); return result; } function createDebugger(namespace) { const newDebugger = Object.assign(debug, { enabled: enabled(namespace), destroy, log: debugObj.log, namespace, extend, }); function debug(...args) { if (!newDebugger.enabled) { return; } if (args.length > 0) { args[0] = `${namespace} ${args[0]}`; } newDebugger.log(...args); } debuggers.push(newDebugger); return newDebugger; } function destroy() { const index = debuggers.indexOf(this); if (index >= 0) { debuggers.splice(index, 1); return true; } return false; } function extend(namespace) { const newDebugger = createDebugger(`${this.namespace}:${namespace}`); newDebugger.log = this.log; return newDebugger; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const TYPESPEC_RUNTIME_LOG_LEVELS = ["verbose", "info", "warning", "error"]; const levelMap = { verbose: 400, info: 300, warning: 200, error: 100, }; function patchLogMethod(parent, child) { child.log = (...args) => { parent.log(...args); }; } function isTypeSpecRuntimeLogLevel(level) { return TYPESPEC_RUNTIME_LOG_LEVELS.includes(level); } /** * Creates a logger context base on the provided options. * @param options - The options for creating a logger context. * @returns The logger context. */ function createLoggerContext(options) { const registeredLoggers = new Set(); const logLevelFromEnv = getEnvironmentVariable(options.logLevelEnvVarName); let logLevel; const clientLogger = debugObj(options.namespace); clientLogger.log = (...args) => { debugObj.log(...args); }; function contextSetLogLevel(level) { if (level && !isTypeSpecRuntimeLogLevel(level)) { throw new Error(`Unknown log level '${level}'. Acceptable values: ${TYPESPEC_RUNTIME_LOG_LEVELS.join(",")}`); } logLevel = level; const enabledNamespaces = []; for (const logger of registeredLoggers) { if (shouldEnable(logger)) { enabledNamespaces.push(logger.namespace); } } debugObj.enable(enabledNamespaces.join(",")); } if (logLevelFromEnv) { // avoid calling setLogLevel because we don't want a mis-set environment variable to crash if (isTypeSpecRuntimeLogLevel(logLevelFromEnv)) { contextSetLogLevel(logLevelFromEnv); } else { console.error(`${options.logLevelEnvVarName} set to unknown log level '${logLevelFromEnv}'; logging is not enabled. Acceptable values: ${TYPESPEC_RUNTIME_LOG_LEVELS.join(", ")}.`); } } function shouldEnable(logger) { return Boolean(logLevel && levelMap[logger.level] <= levelMap[logLevel]); } function createLogger(parent, level) { const logger = Object.assign(parent.extend(level), { level, }); patchLogMethod(parent, logger); if (shouldEnable(logger)) { const enabledNamespaces = debugObj.disable(); debugObj.enable(enabledNamespaces + "," + logger.namespace); } registeredLoggers.add(logger); return logger; } function contextGetLogLevel() { return logLevel; } function contextCreateClientLogger(namespace) { const clientRootLogger = clientLogger.extend(namespace); patchLogMethod(clientLogger, clientRootLogger); return { error: createLogger(clientRootLogger, "error"), warning: createLogger(clientRootLogger, "warning"), info: createLogger(clientRootLogger, "info"), verbose: createLogger(clientRootLogger, "verbose"), }; } return { setLogLevel: contextSetLogLevel, getLogLevel: contextGetLogLevel, createClientLogger: contextCreateClientLogger, logger: clientLogger, }; } const context$1 = createLoggerContext({ logLevelEnvVarName: "TYPESPEC_RUNTIME_LOG_LEVEL", namespace: "typeSpecRuntime", }); /** * Creates a logger for use by the SDKs that inherits from `TypeSpecRuntimeLogger`. * @param namespace - The name of the SDK package. * @hidden */ function createClientLogger$1(namespace) { return context$1.createClientLogger(namespace); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function normalizeName(name) { return name.toLowerCase(); } /** * Removes CR and LF characters from a header value to prevent obs-fold * (line folding) sequences, as forbidden by RFC 7230 §3.2.4. * @param value - The header value to sanitize. */ function normalizeValue(value) { return String(value) .trim() .replace(/[\r\n]/g, ""); } function* headerIterator(map) { for (const entry of map.values()) { yield [entry.name, entry.value]; } } class HttpHeadersImpl { _headersMap; constructor(rawHeaders) { this._headersMap = new Map(); if (rawHeaders) { for (const headerName of Object.keys(rawHeaders)) { this.set(headerName, rawHeaders[headerName]); } } } /** * Set a header in this collection with the provided name and value. The name is * case-insensitive. * @param name - The name of the header to set. This value is case-insensitive. * @param value - The value of the header to set. */ set(name, value) { this._headersMap.set(normalizeName(name), { name, value: normalizeValue(value) }); } /** * Get the header value for the provided header name, or undefined if no header exists in this * collection with the provided name. * @param name - The name of the header. This value is case-insensitive. */ get(name) { return this._headersMap.get(normalizeName(name))?.value; } /** * Get whether or not this header collection contains a header entry for the provided header name. * @param name - The name of the header to set. This value is case-insensitive. */ has(name) { return this._headersMap.has(normalizeName(name)); } /** * Remove the header with the provided headerName. * @param name - The name of the header to remove. */ delete(name) { this._headersMap.delete(normalizeName(name)); } /** * Get the JSON object representation of this HTTP header collection. */ toJSON(options = {}) { const result = {}; if (options.preserveCase) { for (const entry of this._headersMap.values()) { result[entry.name] = entry.value; } } else { for (const [normalizedName, entry] of this._headersMap) { result[normalizedName] = entry.value; } } return result; } /** * Get the string representation of this HTTP header collection. */ toString() { return JSON.stringify(this.toJSON({ preserveCase: true })); } /** * Iterate over tuples of header [name, value] pairs. */ [Symbol.iterator]() { return headerIterator(this._headersMap); } } /** * Creates an object that satisfies the `HttpHeaders` interface. * @param rawHeaders - A simple object representing initial headers */ function createHttpHeaders$1(rawHeaders) { return new HttpHeadersImpl(rawHeaders); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Generated Universally Unique Identifier * * @returns RFC4122 v4 UUID. */ function randomUUID$1() { return crypto.randomUUID(); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. class PipelineRequestImpl { url; method; headers; timeout; withCredentials; body; multipartBody; formData; streamResponseStatusCodes; enableBrowserStreams; proxySettings; disableKeepAlive; abortSignal; requestId; allowInsecureConnection; onUploadProgress; onDownloadProgress; requestOverrides; authSchemes; constructor(options) { this.url = options.url; this.body = options.body; this.headers = options.headers ?? createHttpHeaders$1(); this.method = options.method ?? "GET"; this.timeout = options.timeout ?? 0; this.multipartBody = options.multipartBody; this.formData = options.formData; this.disableKeepAlive = options.disableKeepAlive ?? false; this.proxySettings = options.proxySettings; this.streamResponseStatusCodes = options.streamResponseStatusCodes; this.withCredentials = options.withCredentials ?? false; this.abortSignal = options.abortSignal; this.onUploadProgress = options.onUploadProgress; this.onDownloadProgress = options.onDownloadProgress; this.requestId = options.requestId || randomUUID$1(); this.allowInsecureConnection = options.allowInsecureConnection ?? false; this.enableBrowserStreams = options.enableBrowserStreams ?? false; this.requestOverrides = options.requestOverrides; this.authSchemes = options.authSchemes; } } /** * Creates a new pipeline request with the given options. * This method is to allow for the easy setting of default values and not required. * @param options - The options to create the request with. */ function createPipelineRequest$1(options) { return new PipelineRequestImpl(options); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const ValidPhaseNames = new Set(["Deserialize", "Serialize", "Retry", "Sign"]); /** * A private implementation of Pipeline. * Do not export this class from the package. * @internal */ class HttpPipeline { _policies = []; _orderedPolicies; constructor(policies) { this._policies = policies?.slice(0) ?? []; this._orderedPolicies = undefined; } addPolicy(policy, options = {}) { if (options.phase && options.afterPhase) { throw new Error("Policies inside a phase cannot specify afterPhase."); } if (options.phase && !ValidPhaseNames.has(options.phase)) { throw new Error(`Invalid phase name: ${options.phase}`); } if (options.afterPhase && !ValidPhaseNames.has(options.afterPhase)) { throw new Error(`Invalid afterPhase name: ${options.afterPhase}`); } this._policies.push({ policy, options, }); this._orderedPolicies = undefined; } removePolicy(options) { const removedPolicies = []; this._policies = this._policies.filter((policyDescriptor) => { if ((options.name && policyDescriptor.policy.name === options.name) || (options.phase && policyDescriptor.options.phase === options.phase)) { removedPolicies.push(policyDescriptor.policy); return false; } else { return true; } }); this._orderedPolicies = undefined; return removedPolicies; } sendRequest(httpClient, request) { const policies = this.getOrderedPolicies(); const pipeline = policies.reduceRight((next, policy) => { return (req) => { return policy.sendRequest(req, next); }; }, (req) => httpClient.sendRequest(req)); return pipeline(request); } getOrderedPolicies() { if (!this._orderedPolicies) { this._orderedPolicies = this.orderPolicies(); } return this._orderedPolicies; } clone() { return new HttpPipeline(this._policies); } static create() { return new HttpPipeline(); } orderPolicies() { /** * The goal of this method is to reliably order pipeline policies * based on their declared requirements when they were added. * * Order is first determined by phase: * * 1. Serialize Phase * 2. Policies not in a phase * 3. Deserialize Phase * 4. Retry Phase * 5. Sign Phase * * Within each phase, policies are executed in the order * they were added unless they were specified to execute * before/after other policies or after a particular phase. * * To determine the final order, we will walk the policy list * in phase order multiple times until all dependencies are * satisfied. * * `afterPolicies` are the set of policies that must be * executed before a given policy. This requirement is * considered satisfied when each of the listed policies * have been scheduled. * * `beforePolicies` are the set of policies that must be * executed after a given policy. Since this dependency * can be expressed by converting it into a equivalent * `afterPolicies` declarations, they are normalized * into that form for simplicity. * * An `afterPhase` dependency is considered satisfied when all * policies in that phase have scheduled. * */ const result = []; // Track all policies we know about. const policyMap = new Map(); function createPhase(name) { return { name, policies: new Set(), hasRun: false, hasAfterPolicies: false, }; } // Track policies for each phase. const serializePhase = createPhase("Serialize"); const noPhase = createPhase("None"); const deserializePhase = createPhase("Deserialize"); const retryPhase = createPhase("Retry"); const signPhase = createPhase("Sign"); // a list of phases in order const orderedPhases = [serializePhase, noPhase, deserializePhase, retryPhase, signPhase]; // Small helper function to map phase name to each Phase function getPhase(phase) { if (phase === "Retry") { return retryPhase; } else if (phase === "Serialize") { return serializePhase; } else if (phase === "Deserialize") { return deserializePhase; } else if (phase === "Sign") { return signPhase; } else { return noPhase; } } // First walk each policy and create a node to track metadata. for (const descriptor of this._policies) { const policy = descriptor.policy; const options = descriptor.options; const policyName = policy.name; if (policyMap.has(policyName)) { throw new Error("Duplicate policy names not allowed in pipeline"); } const node = { policy, dependsOn: new Set(), dependants: new Set(), }; if (options.afterPhase) { node.afterPhase = getPhase(options.afterPhase); node.afterPhase.hasAfterPolicies = true; } policyMap.set(policyName, node); const phase = getPhase(options.phase); phase.policies.add(node); } // Now that each policy has a node, connect dependency references. for (const descriptor of this._policies) { const { policy, options } = descriptor; const policyName = policy.name; const node = policyMap.get(policyName); if (!node) { throw new Error(`Missing node for policy ${policyName}`); } if (options.afterPolicies) { for (const afterPolicyName of options.afterPolicies) { const afterNode = policyMap.get(afterPolicyName); if (afterNode) { // Linking in both directions helps later // when we want to notify dependants. node.dependsOn.add(afterNode); afterNode.dependants.add(node); } } } if (options.beforePolicies) { for (const beforePolicyName of options.beforePolicies) { const beforeNode = policyMap.get(beforePolicyName); if (beforeNode) { // To execute before another node, make it // depend on the current node. beforeNode.dependsOn.add(node); node.dependants.add(beforeNode); } } } } function walkPhase(phase) { phase.hasRun = true; // Sets iterate in insertion order for (const node of phase.policies) { if (node.afterPhase && (!node.afterPhase.hasRun || node.afterPhase.policies.size)) { // If this node is waiting on a phase to complete, // we need to skip it for now. // Even if the phase is empty, we should wait for it // to be walked to avoid re-ordering policies. continue; } if (node.dependsOn.size === 0) { // If there's nothing else we're waiting for, we can // add this policy to the result list. result.push(node.policy); // Notify anything that depends on this policy that // the policy has been scheduled. for (const dependant of node.dependants) { dependant.dependsOn.delete(node); } policyMap.delete(node.policy.name); phase.policies.delete(node); } } } function walkPhases() { for (const phase of orderedPhases) { walkPhase(phase); // if the phase isn't complete if (phase.policies.size > 0 && phase !== noPhase) { if (!noPhase.hasRun) { // Try running noPhase to see if that unblocks this phase next tick. // This can happen if a phase that happens before noPhase // is waiting on a noPhase policy to complete. walkPhase(noPhase); } // Don't proceed to the next phase until this phase finishes. return; } if (phase.hasAfterPolicies) { // Run any policies unblocked by this phase walkPhase(noPhase); } } } // Iterate until we've put every node in the result list. let iteration = 0; while (policyMap.size > 0) { iteration++; const initialResultLength = result.length; // Keep walking each phase in order until we can order every node. walkPhases(); // The result list *should* get at least one larger each time // after the first full pass. // Otherwise, we're going to loop forever. if (result.length <= initialResultLength && iteration > 1) { throw new Error("Cannot satisfy policy dependencies due to requirements cycle."); } } return result; } } /** * Creates a totally empty pipeline. * Useful for testing or creating a custom one. */ function createEmptyPipeline$1() { return HttpPipeline.create(); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Helper to determine when an input is a generic JS object. * @returns true when input is an object type that is not null, Array, RegExp, or Date. */ function isObject(input) { return (typeof input === "object" && input !== null && !Array.isArray(input) && !(input instanceof RegExp) && !(input instanceof Date)); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Typeguard for an error object shape (has name and message) * @param e - Something caught by a catch clause. */ function isError$1(e) { if (isObject(e)) { const hasName = typeof e.name === "string"; const hasMessage = typeof e.message === "string"; return hasName && hasMessage; } return false; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const custom = inspect.custom; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const RedactedString = "REDACTED"; // Make sure this list is up-to-date with the one under core/logger/Readme#Keyconcepts const defaultAllowedHeaderNames = [ "x-ms-client-request-id", "x-ms-return-client-request-id", "x-ms-useragent", "x-ms-correlation-request-id", "x-ms-request-id", "client-request-id", "ms-cv", "return-client-request-id", "traceparent", "Access-Control-Allow-Credentials", "Access-Control-Allow-Headers", "Access-Control-Allow-Methods", "Access-Control-Allow-Origin", "Access-Control-Expose-Headers", "Access-Control-Max-Age", "Access-Control-Request-Headers", "Access-Control-Request-Method", "Origin", "Accept", "Accept-Encoding", "Cache-Control", "Connection", "Content-Length", "Content-Type", "Date", "ETag", "Expires", "If-Match", "If-Modified-Since", "If-None-Match", "If-Unmodified-Since", "Last-Modified", "Pragma", "Request-Id", "Retry-After", "Server", "Transfer-Encoding", "User-Agent", "WWW-Authenticate", ]; const defaultAllowedQueryParameters = ["api-version"]; /** * A utility class to sanitize objects for logging. */ class Sanitizer { allowedHeaderNames; allowedQueryParameters; constructor({ additionalAllowedHeaderNames: allowedHeaderNames = [], additionalAllowedQueryParameters: allowedQueryParameters = [], } = {}) { allowedHeaderNames = defaultAllowedHeaderNames.concat(allowedHeaderNames); allowedQueryParameters = defaultAllowedQueryParameters.concat(allowedQueryParameters); this.allowedHeaderNames = new Set(allowedHeaderNames.map((n) => n.toLowerCase())); this.allowedQueryParameters = new Set(allowedQueryParameters.map((p) => p.toLowerCase())); } /** * Sanitizes an object for logging. * @param obj - The object to sanitize * @returns - The sanitized object as a string */ sanitize(obj) { const seen = new Set(); return JSON.stringify(obj, (key, value) => { // Ensure Errors include their interesting non-enumerable members if (value instanceof Error) { return { ...value, name: value.name, message: value.message, }; } if (key === "headers" && isObject(value)) { return this.sanitizeHeaders(value); } else if (key === "url" && typeof value === "string") { return this.sanitizeUrl(value); } else if (key === "query" && isObject(value)) { return this.sanitizeQuery(value); } else if (key === "body") { // Don't log the request body return undefined; } else if (key === "response") { // Don't log response again return undefined; } else if (key === "operationSpec") { // When using sendOperationRequest, the request carries a massive // field with the autorest spec. No need to log it. return undefined; } else if (Array.isArray(value) || isObject(value)) { if (seen.has(value)) { return "[Circular]"; } seen.add(value); } return value; }, 2); } /** * Sanitizes a URL for logging. * @param value - The URL to sanitize * @returns - The sanitized URL as a string */ sanitizeUrl(value) { if (typeof value !== "string" || value === null || value === "") { return value; } const url = new URL(value); if (!url.search) { return value; } for (const [key] of url.searchParams) { if (!this.allowedQueryParameters.has(key.toLowerCase())) { url.searchParams.set(key, RedactedString); } } return url.toString(); } sanitizeHeaders(obj) { const sanitized = {}; for (const key of Object.keys(obj)) { if (this.allowedHeaderNames.has(key.toLowerCase())) { sanitized[key] = obj[key]; } else { sanitized[key] = RedactedString; } } return sanitized; } sanitizeQuery(value) { if (typeof value !== "object" || value === null) { return value; } const sanitized = {}; for (const k of Object.keys(value)) { if (this.allowedQueryParameters.has(k.toLowerCase())) { sanitized[k] = value[k]; } else { sanitized[k] = RedactedString; } } return sanitized; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const errorSanitizer = new Sanitizer(); /** * A custom error type for failed pipeline requests. */ let RestError$1 = class RestError extends Error { /** * Something went wrong when making the request. * This means the actual request failed for some reason, * such as a DNS issue or the connection being lost. */ static REQUEST_SEND_ERROR = "REQUEST_SEND_ERROR"; /** * This means that parsing the response from the server failed. * It may have been malformed. */ static PARSE_ERROR = "PARSE_ERROR"; /** * The code of the error itself (use statics on RestError if possible.) */ code; /** * The HTTP status code of the request (if applicable.) */ statusCode; /** * The request that was made. * This property is non-enumerable. */ request; /** * The response received (if any.) * This property is non-enumerable. */ response; /** * Bonus property set by the throw site. */ details; constructor(message, options = {}) { super(message); this.name = "RestError"; this.code = options.code; this.statusCode = options.statusCode; // The request and response may contain sensitive information in the headers or body. // To help prevent this sensitive information being accidentally logged, the request and response // properties are marked as non-enumerable here. This prevents them showing up in the output of // JSON.stringify and console.log. Object.defineProperty(this, "request", { value: options.request, enumerable: false }); Object.defineProperty(this, "response", { value: options.response, enumerable: false }); // Only include useful agent information in the request for logging, as the full agent object // may contain large binary data. const agent = this.request?.agent ? { maxFreeSockets: this.request.agent.maxFreeSockets, maxSockets: this.request.agent.maxSockets, } : undefined; // Logging method for util.inspect in Node Object.defineProperty(this, custom, { value: () => { // Extract non-enumerable properties and add them back. This is OK since in this output the request and // response get sanitized. return `RestError: ${this.message} \n ${errorSanitizer.sanitize({ ...this, request: { ...this.request, agent }, response: this.response, })}`; }, enumerable: false, }); Object.setPrototypeOf(this, RestError.prototype); } }; /** * Typeguard for RestError * @param e - Something caught by a catch clause. */ function isRestError$1(e) { if (e instanceof RestError$1) { return true; } return isError$1(e) && e.name === "RestError"; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The helper that transforms bytes with specific character encoding into string * @param bytes - the uint8array bytes * @param format - the format we use to encode the byte * @returns a string of the encoded string */ function uint8ArrayToString$1(bytes, format) { return Buffer.from(bytes).toString(format); } /** * The helper that transforms string to specific character encoded bytes array. * @param value - the string to be converted * @param format - the format we use to decode the value * @returns a uint8array */ function stringToUint8Array$1(value, format) { return Buffer.from(value, format); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const logger$4 = createClientLogger$1("ts-http-runtime"); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const DEFAULT_TLS_SETTINGS = {}; function isReadableStream(body) { return body && typeof body.pipe === "function"; } function isStreamComplete(stream) { if (stream.readable === false) { return Promise.resolve(); } return new Promise((resolve) => { const handler = () => { resolve(); stream.removeListener("close", handler); stream.removeListener("end", handler); stream.removeListener("error", handler); }; stream.on("close", handler); stream.on("end", handler); stream.on("error", handler); }); } function isArrayBuffer(body) { return body && typeof body.byteLength === "number"; } class ReportTransform extends Transform { loadedBytes = 0; progressCallback; // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type _transform(chunk, _encoding, callback) { this.push(chunk); this.loadedBytes += chunk.length; try { this.progressCallback({ loadedBytes: this.loadedBytes }); callback(); } catch (e) { callback(e); } } constructor(progressCallback) { super(); this.progressCallback = progressCallback; } } /** * A HttpClient implementation that uses Node's "https" module to send HTTPS requests. * @internal */ class NodeHttpClient { cachedHttpAgent; cachedHttpsAgents = new WeakMap(); /** * Makes a request over an underlying transport layer and returns the response. * @param request - The request to be made. */ async sendRequest(request) { const abortController = new AbortController(); let abortListener; if (request.abortSignal) { if (request.abortSignal.aborted) { throw new AbortError$3("The operation was aborted. Request has already been canceled."); } abortListener = (event) => { if (event.type === "abort") { abortController.abort(); } }; request.abortSignal.addEventListener("abort", abortListener); } let timeoutId; if (request.timeout > 0) { timeoutId = setTimeout(() => { const sanitizer = new Sanitizer(); logger$4.info(`request to '${sanitizer.sanitizeUrl(request.url)}' timed out. canceling...`); abortController.abort(); }, request.timeout); } const acceptEncoding = request.headers.get("Accept-Encoding"); const shouldDecompress = acceptEncoding?.includes("gzip") || acceptEncoding?.includes("deflate"); let body = typeof request.body === "function" ? request.body() : request.body; if (body && !request.headers.has("Content-Length")) { const bodyLength = getBodyLength(body); if (bodyLength !== null) { request.headers.set("Content-Length", bodyLength); } } let responseStream; try { if (body && request.onUploadProgress) { const onUploadProgress = request.onUploadProgress; const uploadReportStream = new ReportTransform(onUploadProgress); uploadReportStream.on("error", (e) => { logger$4.error("Error in upload progress", e); }); if (isReadableStream(body)) { body.pipe(uploadReportStream); } else { uploadReportStream.end(body); } body = uploadReportStream; } const res = await this.makeRequest(request, abortController, body); if (timeoutId !== undefined) { clearTimeout(timeoutId); } const headers = getResponseHeaders(res); const status = res.statusCode ?? 0; const response = { status, headers, request, }; // Responses to HEAD must not have a body. // If they do return a body, that body must be ignored. if (request.method === "HEAD") { // call resume() and not destroy() to avoid closing the socket // and losing keep alive res.resume(); return response; } responseStream = shouldDecompress ? getDecodedResponseStream(res, headers) : res; const onDownloadProgress = request.onDownloadProgress; if (onDownloadProgress) { const downloadReportStream = new ReportTransform(onDownloadProgress); downloadReportStream.on("error", (e) => { logger$4.error("Error in download progress", e); }); responseStream.pipe(downloadReportStream); responseStream = downloadReportStream; } if ( // Value of POSITIVE_INFINITY in streamResponseStatusCodes is considered as any status code request.streamResponseStatusCodes?.has(Number.POSITIVE_INFINITY) || request.streamResponseStatusCodes?.has(response.status)) { response.readableStreamBody = responseStream; } else { response.bodyAsText = await streamToText(responseStream); } return response; } finally { // clean up event listener if (request.abortSignal && abortListener) { let uploadStreamDone = Promise.resolve(); if (isReadableStream(body)) { uploadStreamDone = isStreamComplete(body); } let downloadStreamDone = Promise.resolve(); if (isReadableStream(responseStream)) { downloadStreamDone = isStreamComplete(responseStream); } Promise.all([uploadStreamDone, downloadStreamDone]) .then(() => { // eslint-disable-next-line promise/always-return if (abortListener) { request.abortSignal?.removeEventListener("abort", abortListener); } }) .catch((e) => { logger$4.warning("Error when cleaning up abortListener on httpRequest", e); }); } } } makeRequest(request, abortController, body) { const url = new URL(request.url); const isInsecure = url.protocol !== "https:"; if (isInsecure && !request.allowInsecureConnection) { throw new Error(`Cannot connect to ${request.url} while allowInsecureConnection is false.`); } const agent = request.agent ?? this.getOrCreateAgent(request, isInsecure); const options = { agent, hostname: url.hostname, path: `${url.pathname}${url.search}`, port: url.port, method: request.method, headers: request.headers.toJSON({ preserveCase: true }), ...request.requestOverrides, }; return new Promise((resolve, reject) => { const req = isInsecure ? http.request(options, resolve) : https.request(options, resolve); req.once("error", (err) => { reject(new RestError$1(err.message, { code: err.code ?? RestError$1.REQUEST_SEND_ERROR, request })); }); abortController.signal.addEventListener("abort", () => { const abortError = new AbortError$3("The operation was aborted. Rejecting from abort signal callback while making request."); req.destroy(abortError); reject(abortError); }); if (body && isReadableStream(body)) { body.pipe(req); } else if (body) { if (typeof body === "string" || Buffer.isBuffer(body)) { req.end(body); } else if (isArrayBuffer(body)) { req.end(ArrayBuffer.isView(body) ? Buffer.from(body.buffer, body.byteOffset, body.byteLength) : Buffer.from(body)); } else { logger$4.error("Unrecognized body type", body); reject(new RestError$1("Unrecognized body type")); } } else { // streams don't like "undefined" being passed as data req.end(); } }); } getOrCreateAgent(request, isInsecure) { const disableKeepAlive = request.disableKeepAlive; // Handle Insecure requests first if (isInsecure) { if (disableKeepAlive) { // keepAlive:false is the default so we don't need a custom Agent return http.globalAgent; } if (!this.cachedHttpAgent) { // If there is no cached agent create a new one and cache it. this.cachedHttpAgent = new http.Agent({ keepAlive: true }); } return this.cachedHttpAgent; } else { if (disableKeepAlive && !request.tlsSettings) { // When there are no tlsSettings and keepAlive is false // we don't need a custom agent return https.globalAgent; } // We use the tlsSettings to index cached clients const tlsSettings = request.tlsSettings ?? DEFAULT_TLS_SETTINGS; // Get the cached agent or create a new one with the // provided values for keepAlive and tlsSettings let agent = this.cachedHttpsAgents.get(tlsSettings); if (agent && agent.options.keepAlive === !disableKeepAlive) { return agent; } logger$4.info("No cached TLS Agent exist, creating a new Agent"); agent = new https.Agent({ // keepAlive is true if disableKeepAlive is false. keepAlive: !disableKeepAlive, // Since we are spreading, if no tslSettings were provided, nothing is added to the agent options. ...tlsSettings, }); this.cachedHttpsAgents.set(tlsSettings, agent); return agent; } } } function getResponseHeaders(res) { const headers = createHttpHeaders$1(); for (const header of Object.keys(res.headers)) { const value = res.headers[header]; if (Array.isArray(value)) { if (value.length > 0) { headers.set(header, value[0]); } } else if (value) { headers.set(header, value); } } return headers; } function getDecodedResponseStream(stream, headers) { const contentEncoding = headers.get("Content-Encoding"); if (contentEncoding === "gzip") { const unzip = zlib.createGunzip(); stream.pipe(unzip); return unzip; } else if (contentEncoding === "deflate") { const inflate = zlib.createInflate(); stream.pipe(inflate); return inflate; } return stream; } function streamToText(stream) { return new Promise((resolve, reject) => { const buffer = []; stream.on("data", (chunk) => { if (Buffer.isBuffer(chunk)) { buffer.push(chunk); } else { buffer.push(Buffer.from(chunk)); } }); stream.on("end", () => { resolve(Buffer.concat(buffer).toString("utf8")); }); stream.on("error", (e) => { if (e && e?.name === "AbortError") { reject(e); } else { reject(new RestError$1(`Error reading response as text: ${e.message}`, { code: RestError$1.PARSE_ERROR, })); } }); }); } /** @internal */ function getBodyLength(body) { if (!body) { return 0; } else if (Buffer.isBuffer(body)) { return body.length; } else if (isReadableStream(body)) { return null; } else if (isArrayBuffer(body)) { return body.byteLength; } else if (typeof body === "string") { return Buffer.from(body).length; } else { return null; } } /** * Create a new HttpClient instance for the NodeJS environment. * @internal */ function createNodeHttpClient() { return new NodeHttpClient(); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Create the correct HttpClient for the current environment. */ function createDefaultHttpClient$1() { return createNodeHttpClient(); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the logPolicy. */ const logPolicyName = "logPolicy"; /** * A policy that logs all requests and responses. * @param options - Options to configure logPolicy. */ function logPolicy$1(options = {}) { const logger = options.logger ?? logger$4.info; const sanitizer = new Sanitizer({ additionalAllowedHeaderNames: options.additionalAllowedHeaderNames, additionalAllowedQueryParameters: options.additionalAllowedQueryParameters, }); return { name: logPolicyName, async sendRequest(request, next) { if (!logger.enabled) { return next(request); } logger(`Request: ${sanitizer.sanitize(request)}`); const response = await next(request); logger(`Response status code: ${response.status}`); logger(`Headers: ${sanitizer.sanitize(response.headers)}`); return response; }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const DEFAULT_RETRY_POLICY_COUNT = 3; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Returns a random integer value between a lower and upper bound, * inclusive of both bounds. * Note that this uses Math.random and isn't secure. If you need to use * this for any kind of security purpose, find a better source of random. * @param min - The smallest integer value allowed. * @param max - The largest integer value allowed. */ function getRandomIntegerInclusive(min, max) { // Make sure inputs are integers. min = Math.ceil(min); max = Math.floor(max); // Pick a random offset from zero to the size of the range. // Since Math.random() can never return 1, we have to make the range one larger // in order to be inclusive of the maximum value after we take the floor. const offset = Math.floor(Math.random() * (max - min + 1)); return offset + min; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Calculates the delay interval for retry attempts using exponential delay with jitter. * @param retryAttempt - The current retry attempt number. * @param config - The exponential retry configuration. * @returns An object containing the calculated retry delay. */ function calculateRetryDelay(retryAttempt, config) { // Exponentially increase the delay each time const exponentialDelay = config.retryDelayInMs * Math.pow(2, retryAttempt); // Don't let the delay exceed the maximum const clampedDelay = Math.min(config.maxRetryDelayInMs, exponentialDelay); // Allow the final value to have some "jitter" (within 50% of the delay size) so // that retries across multiple clients don't occur simultaneously. const retryAfterInMs = clampedDelay / 2 + getRandomIntegerInclusive(0, clampedDelay / 2); return { retryAfterInMs }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const StandardAbortMessage$1 = "The operation was aborted."; /** * A wrapper for setTimeout that resolves a promise after delayInMs milliseconds. * @param delayInMs - The number of milliseconds to be delayed. * @param value - The value to be resolved with after a timeout of t milliseconds. * @param options - The options for delay - currently abort options * - abortSignal - The abortSignal associated with containing operation. * - abortErrorMsg - The abort error message associated with containing operation. * @returns Resolved promise */ function delay$2(delayInMs, value, options) { return new Promise((resolve, reject) => { let timer = undefined; let onAborted = undefined; const rejectOnAbort = () => { return reject(new AbortError$3(options?.abortErrorMsg ? options?.abortErrorMsg : StandardAbortMessage$1)); }; const removeListeners = () => { if (options?.abortSignal && onAborted) { options.abortSignal.removeEventListener("abort", onAborted); } }; onAborted = () => { if (timer) { clearTimeout(timer); } removeListeners(); return rejectOnAbort(); }; if (options?.abortSignal && options.abortSignal.aborted) { return rejectOnAbort(); } timer = setTimeout(() => { removeListeners(); resolve(value); }, delayInMs); if (options?.abortSignal) { options.abortSignal.addEventListener("abort", onAborted); } }); } /** * @internal * @returns the parsed value or undefined if the parsed value is invalid. */ function parseHeaderValueAsNumber(response, headerName) { const value = response.headers.get(headerName); if (!value) return; const valueAsNum = Number(value); if (Number.isNaN(valueAsNum)) return; return valueAsNum; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The header that comes back from services representing * the amount of time (minimum) to wait to retry (in seconds or timestamp after which we can retry). */ const RetryAfterHeader = "Retry-After"; /** * The headers that come back from services representing * the amount of time (minimum) to wait to retry. * * "retry-after-ms", "x-ms-retry-after-ms" : milliseconds * "Retry-After" : seconds or timestamp */ const AllRetryAfterHeaders = ["retry-after-ms", "x-ms-retry-after-ms", RetryAfterHeader]; /** * A response is a throttling retry response if it has a throttling status code (429 or 503), * as long as one of the [ "Retry-After" or "retry-after-ms" or "x-ms-retry-after-ms" ] headers has a valid value. * * Returns the `retryAfterInMs` value if the response is a throttling retry response. * If not throttling retry response, returns `undefined`. * * @internal */ function getRetryAfterInMs(response) { if (!(response && [429, 503].includes(response.status))) return undefined; try { // Headers: "retry-after-ms", "x-ms-retry-after-ms", "Retry-After" for (const header of AllRetryAfterHeaders) { const retryAfterValue = parseHeaderValueAsNumber(response, header); if (retryAfterValue === 0 || retryAfterValue) { // "Retry-After" header ==> seconds // "retry-after-ms", "x-ms-retry-after-ms" headers ==> milli-seconds const multiplyingFactor = header === RetryAfterHeader ? 1000 : 1; return retryAfterValue * multiplyingFactor; // in milli-seconds } } // RetryAfterHeader ("Retry-After") has a special case where it might be formatted as a date instead of a number of seconds const retryAfterHeader = response.headers.get(RetryAfterHeader); if (!retryAfterHeader) return; const date = Date.parse(retryAfterHeader); const diff = date - Date.now(); // negative diff would mean a date in the past, so retry asap with 0 milliseconds return Number.isFinite(diff) ? Math.max(0, diff) : undefined; } catch { return undefined; } } /** * A response is a retry response if it has a throttling status code (429 or 503), * as long as one of the [ "Retry-After" or "retry-after-ms" or "x-ms-retry-after-ms" ] headers has a valid value. */ function isThrottlingRetryResponse(response) { return Number.isFinite(getRetryAfterInMs(response)); } function throttlingRetryStrategy() { return { name: "throttlingRetryStrategy", retry({ response }) { const retryAfterInMs = getRetryAfterInMs(response); if (!Number.isFinite(retryAfterInMs)) { return { skipStrategy: true }; } return { retryAfterInMs, }; }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // intervals are in milliseconds const DEFAULT_CLIENT_RETRY_INTERVAL = 1000; const DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 64; /** * A retry strategy that retries with an exponentially increasing delay in these two cases: * - When there are errors in the underlying transport layer (e.g. DNS lookup failures). * - Or otherwise if the outgoing request fails (408, greater or equal than 500, except for 501 and 505). */ function exponentialRetryStrategy(options = {}) { const retryInterval = options.retryDelayInMs ?? DEFAULT_CLIENT_RETRY_INTERVAL; const maxRetryInterval = options.maxRetryDelayInMs ?? DEFAULT_CLIENT_MAX_RETRY_INTERVAL; return { name: "exponentialRetryStrategy", retry({ retryCount, response, responseError }) { const matchedSystemError = isSystemError(responseError); const ignoreSystemErrors = matchedSystemError && options.ignoreSystemErrors; const isExponential = isExponentialRetryResponse(response); const ignoreExponentialResponse = isExponential && options.ignoreHttpStatusCodes; const unknownResponse = response && (isThrottlingRetryResponse(response) || !isExponential); if (unknownResponse || ignoreExponentialResponse || ignoreSystemErrors) { return { skipStrategy: true }; } if (responseError && !matchedSystemError && !isExponential) { return { errorToThrow: responseError }; } return calculateRetryDelay(retryCount, { retryDelayInMs: retryInterval, maxRetryDelayInMs: maxRetryInterval, }); }, }; } /** * A response is a retry response if it has status codes: * - 408, or * - Greater or equal than 500, except for 501 and 505. */ function isExponentialRetryResponse(response) { return Boolean(response && response.status !== undefined && (response.status >= 500 || response.status === 408) && response.status !== 501 && response.status !== 505); } /** * Determines whether an error from a pipeline response was triggered in the network layer. */ function isSystemError(err) { if (!err) { return false; } return (err.code === "ETIMEDOUT" || err.code === "ESOCKETTIMEDOUT" || err.code === "ECONNREFUSED" || err.code === "ECONNRESET" || err.code === "ENOENT" || err.code === "ENOTFOUND"); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const retryPolicyLogger = createClientLogger$1("ts-http-runtime retryPolicy"); /** * The programmatic identifier of the retryPolicy. */ const retryPolicyName = "retryPolicy"; /** * retryPolicy is a generic policy to enable retrying requests when certain conditions are met */ function retryPolicy(strategies, options = { maxRetries: DEFAULT_RETRY_POLICY_COUNT }) { const logger = options.logger || retryPolicyLogger; return { name: retryPolicyName, async sendRequest(request, next) { let response; let responseError; let retryCount = -1; retryRequest: while (true) { retryCount += 1; response = undefined; responseError = undefined; try { logger.info(`Retry ${retryCount}: Attempting to send request`, request.requestId); response = await next(request); logger.info(`Retry ${retryCount}: Received a response from request`, request.requestId); } catch (e) { logger.error(`Retry ${retryCount}: Received an error from request`, request.requestId); // RestErrors are valid targets for the retry strategies. // If none of the retry strategies can work with them, they will be thrown later in this policy. // If the received error is not a RestError, it is immediately thrown. if (!isRestError$1(e)) { throw e; } responseError = e; response = e.response; } if (request.abortSignal?.aborted) { logger.error(`Retry ${retryCount}: Request aborted.`); const abortError = new AbortError$3(); throw abortError; } if (retryCount >= (options.maxRetries ?? DEFAULT_RETRY_POLICY_COUNT)) { logger.info(`Retry ${retryCount}: Maximum retries reached. Returning the last received response, or throwing the last received error.`); if (responseError) { throw responseError; } else if (response) { return response; } else { throw new Error("Maximum retries reached with no response or error to throw"); } } logger.info(`Retry ${retryCount}: Processing ${strategies.length} retry strategies.`); strategiesLoop: for (const strategy of strategies) { const strategyLogger = strategy.logger || logger; strategyLogger.info(`Retry ${retryCount}: Processing retry strategy ${strategy.name}.`); const modifiers = strategy.retry({ retryCount, response, responseError, }); if (modifiers.skipStrategy) { strategyLogger.info(`Retry ${retryCount}: Skipped.`); continue strategiesLoop; } const { errorToThrow, retryAfterInMs, redirectTo } = modifiers; if (errorToThrow) { strategyLogger.error(`Retry ${retryCount}: Retry strategy ${strategy.name} throws error:`, errorToThrow); throw errorToThrow; } if (retryAfterInMs || retryAfterInMs === 0) { strategyLogger.info(`Retry ${retryCount}: Retry strategy ${strategy.name} retries after ${retryAfterInMs}`); await delay$2(retryAfterInMs, undefined, { abortSignal: request.abortSignal }); continue retryRequest; } if (redirectTo) { strategyLogger.info(`Retry ${retryCount}: Retry strategy ${strategy.name} redirects to ${redirectTo}`); request.url = redirectTo; continue retryRequest; } } if (responseError) { logger.info(`None of the retry strategies could work with the received error. Throwing it.`); throw responseError; } if (response) { logger.info(`None of the retry strategies could work with the received response. Returning it.`); return response; } // If all the retries skip and there's no response, // we're still in the retry loop, so a new request will be sent // until `maxRetries` is reached. } }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Name of the {@link defaultRetryPolicy} */ const defaultRetryPolicyName = "defaultRetryPolicy"; /** * A policy that retries according to three strategies: * - When the server sends a 429 response with a Retry-After header. * - When there are errors in the underlying transport layer (e.g. DNS lookup failures). * - Or otherwise if the outgoing request fails, it will retry with an exponentially increasing delay. */ function defaultRetryPolicy$1(options = {}) { return { name: defaultRetryPolicyName, sendRequest: retryPolicy([throttlingRetryStrategy(), exponentialRetryStrategy(options)], { maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY_COUNT, }).sendRequest, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * If the request body is a native FormData, convert it to our FormDataMap * representation and clear the body. Node.js's HTTP stack doesn't handle * FormData natively, so the pipeline must serialize it later. * * @internal */ function convertBodyToFormDataMap(body) { if (typeof FormData !== "undefined" && body instanceof FormData) { const formDataMap = {}; for (const [key, value] of body.entries()) { const existing = formDataMap[key]; if (Array.isArray(existing)) { existing.push(value); } else { formDataMap[key] = existing !== undefined ? [existing, value] : [value]; } } return formDataMap; } return undefined; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the formDataPolicy. */ const formDataPolicyName = "formDataPolicy"; /** * A policy that encodes FormData on the request into the body. */ function formDataPolicy$1() { return { name: formDataPolicyName, async sendRequest(request, next) { const converted = convertBodyToFormDataMap(request.body); if (converted) { request.formData = converted; request.body = undefined; } if (request.formData) { const contentType = request.headers.get("Content-Type"); if (contentType && contentType.indexOf("application/x-www-form-urlencoded") !== -1) { request.body = wwwFormUrlEncode(request.formData); } else { await prepareFormData(request.formData, request); } request.formData = undefined; } return next(request); }, }; } function wwwFormUrlEncode(formData) { const urlSearchParams = new URLSearchParams(); for (const [key, value] of Object.entries(formData)) { if (Array.isArray(value)) { for (const subValue of value) { urlSearchParams.append(key, subValue.toString()); } } else { urlSearchParams.append(key, value.toString()); } } return urlSearchParams.toString(); } async function prepareFormData(formData, request) { // validate content type (multipart/form-data) const contentType = request.headers.get("Content-Type"); if (contentType && !contentType.startsWith("multipart/form-data")) { // content type is specified and is not multipart/form-data. Exit. return; } request.headers.set("Content-Type", contentType ?? "multipart/form-data"); // set body to MultipartRequestBody using content from FormDataMap const parts = []; for (const [fieldName, values] of Object.entries(formData)) { for (const value of Array.isArray(values) ? values : [values]) { if (typeof value === "string") { parts.push({ headers: createHttpHeaders$1({ "Content-Disposition": `form-data; name="${fieldName}"`, }), body: stringToUint8Array$1(value, "utf-8"), }); } else if (value === undefined || value === null || typeof value !== "object") { throw new Error(`Unexpected value for key ${fieldName}: ${value}. Value should be serialized to string first.`); } else { // using || instead of ?? here since if value.name is empty we should create a file name const fileName = value.name || "blob"; const headers = createHttpHeaders$1(); headers.set("Content-Disposition", `form-data; name="${fieldName}"; filename="${fileName}"`); // again, || is used since an empty value.type means the content type is unset headers.set("Content-Type", value.type || "application/octet-stream"); parts.push({ headers, body: value, }); } } } request.multipartBody = { parts }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Name of the Agent Policy */ const agentPolicyName = "agentPolicy"; /** * Gets a pipeline policy that sets http.agent */ function agentPolicy$1(agent) { return { name: agentPolicyName, sendRequest: async (req, next) => { // Users may define an agent on the request, honor it over the client level one if (!req.agent) { req.agent = agent; } return next(req); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Name of the TLS Policy */ const tlsPolicyName = "tlsPolicy"; /** * Gets a pipeline policy that adds the client certificate to the HttpClient agent for authentication. */ function tlsPolicy$1(tlsSettings) { return { name: tlsPolicyName, sendRequest: async (req, next) => { // Users may define a request tlsSettings, honor those over the client level one if (!req.tlsSettings) { req.tlsSettings = tlsSettings; } return next(req); }, }; } var distExports$1 = requireDist(); var distExports = requireDist$1(); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const HTTPS_PROXY = "HTTPS_PROXY"; const HTTP_PROXY = "HTTP_PROXY"; const ALL_PROXY = "ALL_PROXY"; const NO_PROXY = "NO_PROXY"; /** * The programmatic identifier of the proxyPolicy. */ const proxyPolicyName = "proxyPolicy"; /** * Stores the patterns specified in NO_PROXY environment variable. * @internal */ const globalNoProxyList = []; let noProxyListLoaded = false; /** A cache of whether a host should bypass the proxy. */ const globalBypassedMap = new Map(); function getEnvironmentValue(name) { if (process.env[name]) { return process.env[name]; } else if (process.env[name.toLowerCase()]) { return process.env[name.toLowerCase()]; } return undefined; } function loadEnvironmentProxyValue() { if (!process) { return undefined; } const httpsProxy = getEnvironmentValue(HTTPS_PROXY); const allProxy = getEnvironmentValue(ALL_PROXY); const httpProxy = getEnvironmentValue(HTTP_PROXY); return httpsProxy || allProxy || httpProxy; } /** * Check whether the host of a given `uri` matches any pattern in the no proxy list. * If there's a match, any request sent to the same host shouldn't have the proxy settings set. * This implementation is a port of https://github.com/Azure/azure-sdk-for-net/blob/8cca811371159e527159c7eb65602477898683e2/sdk/core/Azure.Core/src/Pipeline/Internal/HttpEnvironmentProxy.cs#L210 */ function isBypassed(uri, noProxyList, bypassedMap) { if (noProxyList.length === 0) { return false; } const host = new URL(uri).hostname; if (bypassedMap?.has(host)) { return bypassedMap.get(host); } let isBypassedFlag = false; for (const pattern of noProxyList) { if (pattern[0] === ".") { // This should match either domain it self or any subdomain or host // .foo.com will match foo.com it self or *.foo.com if (host.endsWith(pattern)) { isBypassedFlag = true; } else { if (host.length === pattern.length - 1 && host === pattern.slice(1)) { isBypassedFlag = true; } } } else { if (host === pattern) { isBypassedFlag = true; } } } bypassedMap?.set(host, isBypassedFlag); return isBypassedFlag; } function loadNoProxy() { const noProxy = getEnvironmentValue(NO_PROXY); noProxyListLoaded = true; if (noProxy) { return noProxy .split(",") .map((item) => item.trim()) .filter((item) => item.length); } return []; } /** * This method converts a proxy url into `ProxySettings` for use with ProxyPolicy. * If no argument is given, it attempts to parse a proxy URL from the environment * variables `HTTPS_PROXY` or `HTTP_PROXY`. * @param proxyUrl - The url of the proxy to use. May contain authentication information. * @deprecated - Internally this method is no longer necessary when setting proxy information. */ function getDefaultProxySettings$1(proxyUrl) { if (!proxyUrl) { proxyUrl = loadEnvironmentProxyValue(); if (!proxyUrl) { return undefined; } } const parsedUrl = new URL(proxyUrl); const schema = parsedUrl.protocol ? parsedUrl.protocol + "//" : ""; return { host: schema + parsedUrl.hostname, port: Number.parseInt(parsedUrl.port || "80"), username: parsedUrl.username, password: parsedUrl.password, }; } /** * This method attempts to parse a proxy URL from the environment * variables `HTTPS_PROXY` or `HTTP_PROXY`. */ function getDefaultProxySettingsInternal() { const envProxy = loadEnvironmentProxyValue(); return envProxy ? new URL(envProxy) : undefined; } function getUrlFromProxySettings(settings) { let parsedProxyUrl; try { parsedProxyUrl = new URL(settings.host); } catch { throw new Error(`Expecting a valid host string in proxy settings, but found "${settings.host}".`); } parsedProxyUrl.port = String(settings.port); if (settings.username) { parsedProxyUrl.username = settings.username; } if (settings.password) { parsedProxyUrl.password = settings.password; } return parsedProxyUrl; } function setProxyAgentOnRequest(request, cachedAgents, proxyUrl) { // Custom Agent should take precedence so if one is present // we should skip to avoid overwriting it. if (request.agent) { return; } const url = new URL(request.url); const isInsecure = url.protocol !== "https:"; if (request.tlsSettings) { logger$4.warning("TLS settings are not supported in combination with custom Proxy, certificates provided to the client will be ignored."); } if (isInsecure) { if (!cachedAgents.httpProxyAgent) { cachedAgents.httpProxyAgent = new distExports.HttpProxyAgent(proxyUrl); } request.agent = cachedAgents.httpProxyAgent; } else { if (!cachedAgents.httpsProxyAgent) { cachedAgents.httpsProxyAgent = new distExports$1.HttpsProxyAgent(proxyUrl); } request.agent = cachedAgents.httpsProxyAgent; } } /** * A policy that allows one to apply proxy settings to all requests. * If not passed static settings, they will be retrieved from the HTTPS_PROXY * or HTTP_PROXY environment variables. * @param proxySettings - ProxySettings to use on each request. * @param options - additional settings, for example, custom NO_PROXY patterns */ function proxyPolicy$1(proxySettings, options) { if (!noProxyListLoaded) { globalNoProxyList.push(...loadNoProxy()); } const defaultProxy = proxySettings ? getUrlFromProxySettings(proxySettings) : getDefaultProxySettingsInternal(); const cachedAgents = {}; return { name: proxyPolicyName, async sendRequest(request, next) { if (!request.proxySettings && defaultProxy && !isBypassed(request.url, globalNoProxyList, globalBypassedMap)) { setProxyAgentOnRequest(request, cachedAgents, defaultProxy); } else if (request.proxySettings) { setProxyAgentOnRequest(request, cachedAgents, getUrlFromProxySettings(request.proxySettings)); } return next(request); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the decompressResponsePolicy. */ const decompressResponsePolicyName$1 = "decompressResponsePolicy"; /** * A policy to enable response decompression according to Accept-Encoding header * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding */ function decompressResponsePolicy$1() { return { name: decompressResponsePolicyName$1, async sendRequest(request, next) { // HEAD requests have no body if (request.method !== "HEAD") { request.headers.set("Accept-Encoding", "gzip,deflate"); } return next(request); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the redirectPolicy. */ const redirectPolicyName$1 = "redirectPolicy"; /** * Methods that are allowed to follow redirects 301 and 302 */ const allowedRedirect = ["GET", "HEAD"]; /** * A policy to follow Location headers from the server in order * to support server-side redirection. * In the browser, this policy is not used. * @param options - Options to control policy behavior. */ function redirectPolicy$1(options = {}) { const { maxRetries = 20, allowCrossOriginRedirects = false } = options; return { name: redirectPolicyName$1, async sendRequest(request, next) { const response = await next(request); return handleRedirect(next, response, maxRetries, allowCrossOriginRedirects); }, }; } async function handleRedirect(next, response, maxRetries, allowCrossOriginRedirects, currentRetries = 0) { const { request, status, headers } = response; const locationHeader = headers.get("location"); if (locationHeader && (status === 300 || (status === 301 && allowedRedirect.includes(request.method)) || (status === 302 && allowedRedirect.includes(request.method)) || (status === 303 && request.method === "POST") || status === 307) && currentRetries < maxRetries) { const url = new URL(locationHeader, request.url); // Only follow redirects to the same origin by default. if (!allowCrossOriginRedirects) { const originalUrl = new URL(request.url); if (url.origin !== originalUrl.origin) { logger$4.verbose(`Skipping cross-origin redirect from ${originalUrl.origin} to ${url.origin}.`); return response; } } request.url = url.toString(); // POST request with Status code 303 should be converted into a // redirected GET request if the redirect url is present in the location header if (status === 303) { request.method = "GET"; request.headers.delete("Content-Length"); delete request.body; } request.headers.delete("Authorization"); const res = await next(request); return handleRedirect(next, res, maxRetries, allowCrossOriginRedirects, currentRetries + 1); } return response; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function isBlob(x) { return x instanceof Blob; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. async function* streamAsyncIterator() { const reader = this.getReader(); try { while (true) { const { done, value } = await reader.read(); if (done) { return; } yield value; } } finally { reader.releaseLock(); } } function makeAsyncIterable(webStream) { if (!webStream[Symbol.asyncIterator]) { webStream[Symbol.asyncIterator] = streamAsyncIterator.bind(webStream); } if (!webStream.values) { webStream.values = streamAsyncIterator.bind(webStream); } } function ensureNodeStream(stream) { if (stream instanceof ReadableStream) { makeAsyncIterable(stream); return Readable.fromWeb(stream); } else { return stream; } } function toStream(source) { if (source instanceof Uint8Array) { return Readable.from(Buffer.from(source)); } else if (isBlob(source)) { return ensureNodeStream(source.stream()); } else { return ensureNodeStream(source); } } /** * Utility function that concatenates a set of binary inputs into one combined output. * * @param sources - array of sources for the concatenation * @returns - in Node, a (() =\> NodeJS.ReadableStream) which, when read, produces a concatenation of all the inputs. * In browser, returns a `Blob` representing all the concatenated inputs. * * @internal */ async function concat(sources) { return function () { const streams = sources.map((x) => (typeof x === "function" ? x() : x)).map(toStream); return Readable.from((async function* () { for (const stream of streams) { for await (const chunk of stream) { yield chunk; } } })()); }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function generateBoundary() { return `----AzSDKFormBoundary${randomUUID$1()}`; } function encodeHeaders(headers) { let result = ""; for (const [key, value] of headers) { result += `${key}: ${value}\r\n`; } return result; } function getLength(source) { if (source instanceof Uint8Array) { return source.byteLength; } else if (isBlob(source)) { // if was created using createFile then -1 means we have an unknown size return source.size === -1 ? undefined : source.size; } else { return undefined; } } function getTotalLength(sources) { let total = 0; for (const source of sources) { const partLength = getLength(source); if (partLength === undefined) { return undefined; } else { total += partLength; } } return total; } async function buildRequestBody(request, parts, boundary) { const sources = [ stringToUint8Array$1(`--${boundary}`, "utf-8"), ...parts.flatMap((part) => [ stringToUint8Array$1("\r\n", "utf-8"), stringToUint8Array$1(encodeHeaders(part.headers), "utf-8"), stringToUint8Array$1("\r\n", "utf-8"), part.body, stringToUint8Array$1(`\r\n--${boundary}`, "utf-8"), ]), stringToUint8Array$1("--\r\n\r\n", "utf-8"), ]; const contentLength = getTotalLength(sources); if (contentLength) { request.headers.set("Content-Length", contentLength); } // The public BodyPart.body type uses Uint8Array (= Uint8Array) for // backward compatibility. Internally, concat requires Uint8Array to ensure // SharedArrayBuffer-backed arrays don't flow into Blob construction. In practice, HTTP // request bodies are always ArrayBuffer-backed, so this narrowing is safe. request.body = await concat(sources); } /** * Name of multipart policy */ const multipartPolicyName$1 = "multipartPolicy"; const maxBoundaryLength = 70; const validBoundaryCharacters = new Set(`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'()+,-./:=?`); function assertValidBoundary(boundary) { if (boundary.length > maxBoundaryLength) { throw new Error(`Multipart boundary "${boundary}" exceeds maximum length of 70 characters`); } if (Array.from(boundary).some((x) => !validBoundaryCharacters.has(x))) { throw new Error(`Multipart boundary "${boundary}" contains invalid characters`); } } /** * Pipeline policy for multipart requests */ function multipartPolicy$1() { return { name: multipartPolicyName$1, async sendRequest(request, next) { if (!request.multipartBody) { return next(request); } if (request.body) { throw new Error("multipartBody and regular body cannot be set at the same time"); } let boundary = request.multipartBody.boundary; const contentTypeHeader = request.headers.get("Content-Type") ?? "multipart/mixed"; const parsedHeader = contentTypeHeader.match(/^(multipart\/[^ ;]+)(?:; *boundary=(.+))?$/); if (!parsedHeader) { throw new Error(`Got multipart request body, but content-type header was not multipart: ${contentTypeHeader}`); } const [, contentType, parsedBoundary] = parsedHeader; if (parsedBoundary && boundary && parsedBoundary !== boundary) { throw new Error(`Multipart boundary was specified as ${parsedBoundary} in the header, but got ${boundary} in the request body`); } boundary ??= parsedBoundary; if (boundary) { assertValidBoundary(boundary); } else { boundary = generateBoundary(); } request.headers.set("Content-Type", `${contentType}; boundary=${boundary}`); await buildRequestBody(request, request.multipartBody.parts, boundary); request.multipartBody = undefined; return next(request); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Creates a totally empty pipeline. * Useful for testing or creating a custom one. */ function createEmptyPipeline() { return createEmptyPipeline$1(); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const context = createLoggerContext({ logLevelEnvVarName: "AZURE_LOG_LEVEL", namespace: "azure", }); /** * Creates a logger for use by the Azure SDKs that inherits from `AzureLogger`. * @param namespace - The name of the SDK package. * @hidden */ function createClientLogger(namespace) { return context.createClientLogger(namespace); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const logger$3 = createClientLogger("core-rest-pipeline"); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A policy that logs all requests and responses. * @param options - Options to configure logPolicy. */ function logPolicy(options = {}) { return logPolicy$1({ logger: logger$3.info, ...options, }); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the redirectPolicy. */ const redirectPolicyName = redirectPolicyName$1; /** * A policy to follow Location headers from the server in order * to support server-side redirection. * In the browser, this policy is not used. * @param options - Options to control policy behavior. */ function redirectPolicy(options = {}) { return redirectPolicy$1(options); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * @internal */ function getHeaderName() { return "User-Agent"; } /** * @internal */ async function setPlatformSpecificData(map) { if (process$1 && process$1.versions) { const osInfo = `${os$1.type()} ${os$1.release()}; ${os$1.arch()}`; if (process$1.versions.bun) { map.set("Bun", `${process$1.versions.bun} (${osInfo})`); } else if (process$1.versions.deno) { map.set("Deno", `${process$1.versions.deno} (${osInfo})`); } else if (process$1.versions.node) { map.set("Node", `${process$1.versions.node} (${osInfo})`); } } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const SDK_VERSION$1 = "1.24.0"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function getUserAgentString$1(telemetryInfo) { const parts = []; for (const [key, value] of telemetryInfo) { const token = value ? `${key}/${value}` : key; parts.push(token); } return parts.join(" "); } /** * @internal */ function getUserAgentHeaderName() { return getHeaderName(); } /** * @internal */ async function getUserAgentValue(prefix) { const runtimeInfo = new Map(); runtimeInfo.set("core-rest-pipeline", SDK_VERSION$1); await setPlatformSpecificData(runtimeInfo); const defaultAgent = getUserAgentString$1(runtimeInfo); const userAgentValue = prefix ? `${prefix} ${defaultAgent}` : defaultAgent; return userAgentValue; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const UserAgentHeaderName = getUserAgentHeaderName(); /** * The programmatic identifier of the userAgentPolicy. */ const userAgentPolicyName = "userAgentPolicy"; /** * A policy that sets the User-Agent header (or equivalent) to reflect * the library version. * @param options - Options to customize the user agent value. */ function userAgentPolicy(options = {}) { const userAgentValue = getUserAgentValue(options.userAgentPrefix); return { name: userAgentPolicyName, async sendRequest(request, next) { if (!request.headers.has(UserAgentHeaderName)) { request.headers.set(UserAgentHeaderName, await userAgentValue); } return next(request); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Private symbol used as key on objects created using createFile containing the * original source of the file object. * * This is used in Node to access the original Node stream without using Blob#stream, which * returns a web stream. This is done to avoid a couple of bugs to do with Blob#stream and * Readable#to/fromWeb in Node versions we support: * - https://github.com/nodejs/node/issues/42694 (fixed in Node 18.14) * - https://github.com/nodejs/node/issues/48916 (fixed in Node 20.6) * * Once these versions are no longer supported, we may be able to stop doing this. * * @internal */ const rawContent = Symbol("rawContent"); /** * Type guard to check if a given object is a blob-like object with a raw content property. */ function hasRawContent(x) { return typeof x[rawContent] === "function"; } /** * Extract the raw content from a given blob-like object. If the input was created using createFile * or createFileFromStream, the exact content passed into createFile/createFileFromStream will be used. * For true instances of Blob and File, returns the actual blob. * * @internal */ function getRawContent$1(blob) { if (hasRawContent(blob)) { return blob[rawContent](); } else { return blob; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Name of multipart policy */ const multipartPolicyName = multipartPolicyName$1; /** * Pipeline policy for multipart requests */ function multipartPolicy() { const tspPolicy = multipartPolicy$1(); return { name: multipartPolicyName, sendRequest: async (request, next) => { if (request.multipartBody) { for (const part of request.multipartBody.parts) { if (hasRawContent(part.body)) { part.body = getRawContent$1(part.body); } } } return tspPolicy.sendRequest(request, next); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the decompressResponsePolicy. */ const decompressResponsePolicyName = decompressResponsePolicyName$1; /** * A policy to enable response decompression according to Accept-Encoding header * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding */ function decompressResponsePolicy() { return decompressResponsePolicy$1(); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A policy that retries according to three strategies: * - When the server sends a 429 response with a Retry-After header. * - When there are errors in the underlying transport layer (e.g. DNS lookup failures). * - Or otherwise if the outgoing request fails, it will retry with an exponentially increasing delay. */ function defaultRetryPolicy(options = {}) { return defaultRetryPolicy$1(options); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A policy that encodes FormData on the request into the body. */ function formDataPolicy() { return formDataPolicy$1(); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. /** * This error is thrown when an asynchronous operation has been aborted. * Check for this error by testing the `name` that the name property of the * error matches `"AbortError"`. * * @example * ```ts * const controller = new AbortController(); * controller.abort(); * try { * doAsyncWork(controller.signal) * } catch (e) { * if (e.name === 'AbortError') { * // handle abort error here. * } * } * ``` */ let AbortError$2 = class AbortError extends Error { constructor(message) { super(message); this.name = "AbortError"; } }; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Creates an abortable promise. * @param buildPromise - A function that takes the resolve and reject functions as parameters. * @param options - The options for the abortable promise. * @returns A promise that can be aborted. */ function createAbortablePromise(buildPromise, options) { const { cleanupBeforeAbort, abortSignal, abortErrorMsg } = options ?? {}; return new Promise((resolve, reject) => { function rejectOnAbort() { reject(new AbortError$2(abortErrorMsg ?? "The operation was aborted.")); } function removeListeners() { abortSignal?.removeEventListener("abort", onAbort); } function onAbort() { cleanupBeforeAbort?.(); removeListeners(); rejectOnAbort(); } if (abortSignal?.aborted) { return rejectOnAbort(); } try { buildPromise((x) => { removeListeners(); resolve(x); }, (x) => { removeListeners(); reject(x); }); } catch (err) { reject(err); } abortSignal?.addEventListener("abort", onAbort); }); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const StandardAbortMessage = "The delay was aborted."; /** * A wrapper for setTimeout that resolves a promise after timeInMs milliseconds. * @param timeInMs - The number of milliseconds to be delayed. * @param options - The options for delay - currently abort options * @returns Promise that is resolved after timeInMs */ function delay$1(timeInMs, options) { let token; const { abortSignal, abortErrorMsg } = {}; return createAbortablePromise((resolve) => { token = setTimeout(resolve, timeInMs); }, { cleanupBeforeAbort: () => clearTimeout(token), abortSignal, abortErrorMsg: abortErrorMsg ?? StandardAbortMessage, }); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Given what is thought to be an error object, return the message if possible. * If the message is missing, returns a stringified version of the input. * @param e - Something thrown from a try block * @returns The error message or a string of the input */ function getErrorMessage(e) { if (isError$1(e)) { return e.message; } else { let stringified; try { if (typeof e === "object" && e) { stringified = JSON.stringify(e); } else { stringified = String(e); } } catch (err) { stringified = "[unable to stringify input]"; } return `Unknown error ${stringified}`; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Typeguard for an error object shape (has name and message) * * @param e - Something caught by a catch clause. */ function isError(e) { return isError$1(e); } /** * Generated Universally Unique Identifier * * @returns RFC4122 v4 UUID. */ function randomUUID() { return randomUUID$1(); } /** * The helper that transforms bytes with specific character encoding into string * @param bytes - the uint8array bytes * @param format - the format we use to encode the byte * @returns a string of the encoded string */ function uint8ArrayToString(bytes, format) { return uint8ArrayToString$1(bytes, format); } /** * The helper that transforms string to specific character encoded bytes array. * @param value - the string to be converted * @param format - the format we use to decode the value * @returns a uint8array */ function stringToUint8Array(value, format) { return stringToUint8Array$1(value, format); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * This method converts a proxy url into `ProxySettings` for use with ProxyPolicy. * If no argument is given, it attempts to parse a proxy URL from the environment * variables `HTTPS_PROXY` or `HTTP_PROXY`. * @param proxyUrl - The url of the proxy to use. May contain authentication information. * @deprecated - Internally this method is no longer necessary when setting proxy information. */ function getDefaultProxySettings(proxyUrl) { return getDefaultProxySettings$1(proxyUrl); } /** * A policy that allows one to apply proxy settings to all requests. * If not passed static settings, they will be retrieved from the HTTPS_PROXY * or HTTP_PROXY environment variables. * @param proxySettings - ProxySettings to use on each request. * @param options - additional settings, for example, custom NO_PROXY patterns */ function proxyPolicy(proxySettings, options) { return proxyPolicy$1(proxySettings); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the setClientRequestIdPolicy. */ const setClientRequestIdPolicyName = "setClientRequestIdPolicy"; /** * Each PipelineRequest gets a unique id upon creation. * This policy passes that unique id along via an HTTP header to enable better * telemetry and tracing. * @param requestIdHeaderName - The name of the header to pass the request ID to. */ function setClientRequestIdPolicy(requestIdHeaderName = "x-ms-client-request-id") { return { name: setClientRequestIdPolicyName, async sendRequest(request, next) { if (!request.headers.has(requestIdHeaderName)) { request.headers.set(requestIdHeaderName, request.requestId); } return next(request); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Gets a pipeline policy that sets http.agent */ function agentPolicy(agent) { return agentPolicy$1(agent); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Gets a pipeline policy that adds the client certificate to the HttpClient agent for authentication. */ function tlsPolicy(tlsSettings) { return tlsPolicy$1(tlsSettings); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** @internal */ const knownContextKeys = { span: Symbol.for("@azure/core-tracing span"), namespace: Symbol.for("@azure/core-tracing namespace"), }; /** * Creates a new {@link TracingContext} with the given options. * @param options - A set of known keys that may be set on the context. * @returns A new {@link TracingContext} with the given options. * * @internal */ function createTracingContext(options = {}) { let context = new TracingContextImpl(options.parentContext); if (options.span) { context = context.setValue(knownContextKeys.span, options.span); } if (options.namespace) { context = context.setValue(knownContextKeys.namespace, options.namespace); } return context; } /** @internal */ class TracingContextImpl { _contextMap; constructor(initialContext) { this._contextMap = initialContext instanceof TracingContextImpl ? new Map(initialContext._contextMap) : new Map(); } setValue(key, value) { const newContext = new TracingContextImpl(this); newContext._contextMap.set(key, value); return newContext; } getValue(key) { return this._contextMap.get(key); } deleteValue(key) { const newContext = new TracingContextImpl(this); newContext._contextMap.delete(key); return newContext; } } var stateExports = requireState(); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // @ts-expect-error The recommended approach to sharing module state between ESM and CJS. // See https://github.com/isaacs/tshy/blob/main/README.md#module-local-state for additional information. /** * Defines the shared state between CJS and ESM by re-exporting the CJS state. */ const state$1 = stateExports.state; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function createDefaultTracingSpan() { return { end: () => { // noop }, isRecording: () => false, recordException: () => { // noop }, setAttribute: () => { // noop }, setStatus: () => { // noop }, addEvent: () => { // noop }, }; } function createDefaultInstrumenter() { return { createRequestHeaders: () => { return {}; }, parseTraceparentHeader: () => { return undefined; }, startSpan: (_name, spanOptions) => { return { span: createDefaultTracingSpan(), tracingContext: createTracingContext({ parentContext: spanOptions.tracingContext }), }; }, withContext(_context, callback, ...callbackArgs) { return callback(...callbackArgs); }, }; } /** * Gets the currently set instrumenter, a No-Op instrumenter by default. * * @returns The currently set instrumenter */ function getInstrumenter() { if (!state$1.instrumenterImplementation) { state$1.instrumenterImplementation = createDefaultInstrumenter(); } return state$1.instrumenterImplementation; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Creates a new tracing client. * * @param options - Options used to configure the tracing client. * @returns - An instance of {@link TracingClient}. */ function createTracingClient(options) { const { namespace, packageName, packageVersion } = options; function startSpan(name, operationOptions, spanOptions) { const startSpanResult = getInstrumenter().startSpan(name, { ...spanOptions, packageName: packageName, packageVersion: packageVersion, tracingContext: operationOptions?.tracingOptions?.tracingContext, }); let tracingContext = startSpanResult.tracingContext; const span = startSpanResult.span; if (!tracingContext.getValue(knownContextKeys.namespace)) { tracingContext = tracingContext.setValue(knownContextKeys.namespace, namespace); } span.setAttribute("az.namespace", tracingContext.getValue(knownContextKeys.namespace)); const updatedOptions = Object.assign({}, operationOptions, { tracingOptions: { ...operationOptions?.tracingOptions, tracingContext }, }); return { span, updatedOptions, }; } async function withSpan(name, operationOptions, callback, spanOptions) { const { span, updatedOptions } = startSpan(name, operationOptions, spanOptions); try { const result = await withContext(updatedOptions.tracingOptions.tracingContext, () => Promise.resolve(callback(updatedOptions, span))); span.setStatus({ status: "success" }); return result; } catch (err) { span.setStatus({ status: "error", error: err }); throw err; } finally { span.end(); } } function withContext(context, callback, ...callbackArgs) { return getInstrumenter().withContext(context, callback, ...callbackArgs); } /** * Parses a traceparent header value into a span identifier. * * @param traceparentHeader - The traceparent header to parse. * @returns An implementation-specific identifier for the span. */ function parseTraceparentHeader(traceparentHeader) { return getInstrumenter().parseTraceparentHeader(traceparentHeader); } /** * Creates a set of request headers to propagate tracing information to a backend. * * @param tracingContext - The context containing the span to serialize. * @returns The set of headers to add to a request. */ function createRequestHeaders(tracingContext) { return getInstrumenter().createRequestHeaders(tracingContext); } return { startSpan, withSpan, withContext, parseTraceparentHeader, createRequestHeaders, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A custom error type for failed pipeline requests. */ // eslint-disable-next-line @typescript-eslint/no-redeclare const RestError = RestError$1; /** * Typeguard for RestError * @param e - Something caught by a catch clause. */ function isRestError(e) { return isRestError$1(e); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the tracingPolicy. */ const tracingPolicyName = "tracingPolicy"; /** * A simple policy to create OpenTelemetry Spans for each request made by the pipeline * that has SpanOptions with a parent. * Requests made without a parent Span will not be recorded. * @param options - Options to configure the telemetry logged by the tracing policy. */ function tracingPolicy(options = {}) { const userAgentPromise = getUserAgentValue(options.userAgentPrefix); const sanitizer = new Sanitizer({ additionalAllowedQueryParameters: options.additionalAllowedQueryParameters, }); const tracingClient = tryCreateTracingClient(); return { name: tracingPolicyName, async sendRequest(request, next) { if (!tracingClient) { return next(request); } const userAgent = await userAgentPromise; const spanAttributes = { "http.url": sanitizer.sanitizeUrl(request.url), "http.method": request.method, "http.user_agent": userAgent, requestId: request.requestId, }; if (userAgent) { spanAttributes["http.user_agent"] = userAgent; } const { span, tracingContext } = tryCreateSpan(tracingClient, request, spanAttributes) ?? {}; if (!span || !tracingContext) { return next(request); } try { const response = await tracingClient.withContext(tracingContext, next, request); tryProcessResponse(span, response); return response; } catch (err) { tryProcessError(span, err); throw err; } }, }; } function tryCreateTracingClient() { try { return createTracingClient({ namespace: "", packageName: "@azure/core-rest-pipeline", packageVersion: SDK_VERSION$1, }); } catch (e) { logger$3.warning(`Error when creating the TracingClient: ${getErrorMessage(e)}`); return undefined; } } function tryCreateSpan(tracingClient, request, spanAttributes) { try { // As per spec, we do not need to differentiate between HTTP and HTTPS in span name. const { span, updatedOptions } = tracingClient.startSpan(`HTTP ${request.method}`, { tracingOptions: request.tracingOptions }, { spanKind: "client", spanAttributes, }); // If the span is not recording, don't do any more work. if (!span.isRecording()) { span.end(); return undefined; } // set headers const headers = tracingClient.createRequestHeaders(updatedOptions.tracingOptions.tracingContext); for (const [key, value] of Object.entries(headers)) { request.headers.set(key, value); } return { span, tracingContext: updatedOptions.tracingOptions.tracingContext }; } catch (e) { logger$3.warning(`Skipping creating a tracing span due to an error: ${getErrorMessage(e)}`); return undefined; } } function tryProcessError(span, error) { try { span.setStatus({ status: "error", error: isError(error) ? error : undefined, }); if (isRestError(error) && error.statusCode) { span.setAttribute("http.status_code", error.statusCode); } span.end(); } catch (e) { logger$3.warning(`Skipping tracing span processing due to an error: ${getErrorMessage(e)}`); } } function tryProcessResponse(span, response) { try { span.setAttribute("http.status_code", response.status); const serviceRequestId = response.headers.get("x-ms-request-id"); if (serviceRequestId) { span.setAttribute("serviceRequestId", serviceRequestId); } // Per semantic conventions, only set the status to error if the status code is 4xx or 5xx. // Otherwise, the status MUST remain unset. // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status if (response.status >= 400) { span.setStatus({ status: "error", }); } span.end(); } catch (e) { logger$3.warning(`Skipping tracing span processing due to an error: ${getErrorMessage(e)}`); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Creates a native AbortSignal which reflects the state of the provided AbortSignalLike. * If the AbortSignalLike is already a native AbortSignal, it is returned as is. * @param abortSignalLike - The AbortSignalLike to wrap. * @returns - An object containing the native AbortSignal and an optional cleanup function. The cleanup function should be called when the AbortSignal is no longer needed. */ function wrapAbortSignalLike(abortSignalLike) { if (abortSignalLike instanceof AbortSignal) { return { abortSignal: abortSignalLike }; } if (abortSignalLike.aborted) { return { abortSignal: AbortSignal.abort("reason" in abortSignalLike ? abortSignalLike.reason : undefined), }; } const controller = new AbortController(); let needsCleanup = true; function cleanup() { if (needsCleanup) { abortSignalLike.removeEventListener("abort", listener); needsCleanup = false; } } function listener() { controller.abort("reason" in abortSignalLike ? abortSignalLike.reason : undefined); cleanup(); } abortSignalLike.addEventListener("abort", listener); return { abortSignal: controller.signal, cleanup }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const wrapAbortSignalLikePolicyName = "wrapAbortSignalLikePolicy"; /** * Policy that ensure that any AbortSignalLike is wrapped in a native AbortSignal for processing by the pipeline. * Since the ts-http-runtime expects a native AbortSignal, this policy is used to ensure that any AbortSignalLike is wrapped in a native AbortSignal. * * @returns - created policy */ function wrapAbortSignalLikePolicy() { return { name: wrapAbortSignalLikePolicyName, sendRequest: async (request, next) => { if (!request.abortSignal) { return next(request); } const { abortSignal, cleanup } = wrapAbortSignalLike(request.abortSignal); request.abortSignal = abortSignal; try { return await next(request); } finally { cleanup?.(); } }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Create a new pipeline with a default set of customizable policies. * @param options - Options to configure a custom pipeline. */ function createPipelineFromOptions(options) { const pipeline = createEmptyPipeline(); { if (options.agent) { pipeline.addPolicy(agentPolicy(options.agent)); } if (options.tlsOptions) { pipeline.addPolicy(tlsPolicy(options.tlsOptions)); } pipeline.addPolicy(proxyPolicy(options.proxyOptions)); pipeline.addPolicy(decompressResponsePolicy()); } pipeline.addPolicy(wrapAbortSignalLikePolicy()); pipeline.addPolicy(formDataPolicy(), { beforePolicies: [multipartPolicyName] }); pipeline.addPolicy(userAgentPolicy(options.userAgentOptions)); pipeline.addPolicy(setClientRequestIdPolicy(options.telemetryOptions?.clientRequestIdHeaderName)); // The multipart policy is added after policies with no phase, so that // policies can be added between it and formDataPolicy to modify // properties (e.g., making the boundary constant in recorded tests). pipeline.addPolicy(multipartPolicy(), { afterPhase: "Deserialize" }); pipeline.addPolicy(defaultRetryPolicy(options.retryOptions), { phase: "Retry" }); pipeline.addPolicy(tracingPolicy({ ...options.userAgentOptions, ...options.loggingOptions }), { afterPhase: "Retry", }); { // Both XHR and Fetch expect to handle redirects automatically, // so only include this policy when we're in Node. pipeline.addPolicy(redirectPolicy(options.redirectOptions), { afterPhase: "Retry" }); } pipeline.addPolicy(logPolicy(options.loggingOptions), { afterPhase: "Sign" }); return pipeline; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Create the correct HttpClient for the current environment. */ function createDefaultHttpClient() { const client = createDefaultHttpClient$1(); return { async sendRequest(request) { // we wrap any AbortSignalLike here since the TypeSpec runtime expects a native AbortSignal. // 99% of the time, this should be a no-op since a native AbortSignal is passed in. const { abortSignal, cleanup } = request.abortSignal ? wrapAbortSignalLike(request.abortSignal) : {}; try { request.abortSignal = abortSignal; return await client.sendRequest(request); } finally { cleanup?.(); } }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Creates an object that satisfies the `HttpHeaders` interface. * @param rawHeaders - A simple object representing initial headers */ function createHttpHeaders(rawHeaders) { return createHttpHeaders$1(rawHeaders); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Creates a new pipeline request with the given options. * This method is to allow for the easy setting of default values and not required. * @param options - The options to create the request with. */ function createPipelineRequest(options) { // Cast required due to difference between ts-http-runtime requiring AbortSignal while core-rest-pipeline allows // the more generic AbortSignalLike. The wrapAbortSignalLike pipeline policy will take care of ensuring that any AbortSignalLike in the request // is converted into a true AbortSignal. return createPipelineRequest$1(options); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // Default options for the cycler if none are provided const DEFAULT_CYCLER_OPTIONS = { forcedRefreshWindowInMs: 1000, // Force waiting for a refresh 1s before the token expires retryIntervalInMs: 3000, // Allow refresh attempts every 3s refreshWindowInMs: 1000 * 60 * 2, // Start refreshing 2m before expiry }; /** * Converts an an unreliable access token getter (which may resolve with null) * into an AccessTokenGetter by retrying the unreliable getter in a regular * interval. * * @param getAccessToken - A function that produces a promise of an access token that may fail by returning null. * @param retryIntervalInMs - The time (in milliseconds) to wait between retry attempts. * @param refreshTimeout - The timestamp after which the refresh attempt will fail, throwing an exception. * @returns - A promise that, if it resolves, will resolve with an access token. */ async function beginRefresh(getAccessToken, retryIntervalInMs, refreshTimeout) { // This wrapper handles exceptions gracefully as long as we haven't exceeded // the timeout. async function tryGetAccessToken() { if (Date.now() < refreshTimeout) { try { return await getAccessToken(); } catch { return null; } } else { const finalToken = await getAccessToken(); // Timeout is up, so throw if it's still null if (finalToken === null) { throw new Error("Failed to refresh access token."); } return finalToken; } } let token = await tryGetAccessToken(); while (token === null) { await delay$1(retryIntervalInMs); token = await tryGetAccessToken(); } return token; } /** * Creates a token cycler from a credential, scopes, and optional settings. * * A token cycler represents a way to reliably retrieve a valid access token * from a TokenCredential. It will handle initializing the token, refreshing it * when it nears expiration, and synchronizes refresh attempts to avoid * concurrency hazards. * * @param credential - the underlying TokenCredential that provides the access * token * @param tokenCyclerOptions - optionally override default settings for the cycler * * @returns - a function that reliably produces a valid access token */ function createTokenCycler(credential, tokenCyclerOptions) { let refreshWorker = null; let token = null; let tenantId; const options = { ...DEFAULT_CYCLER_OPTIONS, ...tokenCyclerOptions, }; /** * This little holder defines several predicates that we use to construct * the rules of refreshing the token. */ const cycler = { /** * Produces true if a refresh job is currently in progress. */ get isRefreshing() { return refreshWorker !== null; }, /** * Produces true if the cycler SHOULD refresh (we are within the refresh * window and not already refreshing) */ get shouldRefresh() { if (token === null) { return true; } if (cycler.isRefreshing) { return false; } if (token.refreshAfterTimestamp && token.refreshAfterTimestamp < Date.now()) { return true; } return token.expiresOnTimestamp - options.refreshWindowInMs < Date.now(); }, /** * Produces true if the cycler MUST refresh (null or nearly-expired * token). */ get mustRefresh() { return (token === null || token.expiresOnTimestamp - options.forcedRefreshWindowInMs < Date.now()); }, }; /** * Starts a refresh job or returns the existing job if one is already * running. */ function refresh(scopes, getTokenOptions) { if (!cycler.isRefreshing) { // We bind `scopes` here to avoid passing it around a lot const tryGetAccessToken = () => credential.getToken(scopes, getTokenOptions); // Take advantage of promise chaining to insert an assignment to `token` // before the refresh can be considered done. refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs, // If we don't have a token, then we should timeout immediately token?.expiresOnTimestamp ?? Date.now()) .then((_token) => { refreshWorker = null; token = _token; tenantId = getTokenOptions.tenantId; return token; }) .catch((reason) => { // We also should reset the refresher if we enter a failed state. All // existing awaiters will throw, but subsequent requests will start a // new retry chain. refreshWorker = null; token = null; tenantId = undefined; throw reason; }); } return refreshWorker; } return async (scopes, tokenOptions) => { // // Simple rules: // - If we MUST refresh, then return the refresh task, blocking // the pipeline until a token is available. // - If we SHOULD refresh, then run refresh but don't return it // (we can still use the cached token). // - Return the token, since it's fine if we didn't return in // step 1. // const hasClaimChallenge = Boolean(tokenOptions.claims); const tenantIdChanged = tenantId !== tokenOptions.tenantId; if (hasClaimChallenge) { // If we've received a claim, we know the existing token isn't valid // We want to clear it so that that refresh worker won't use the old expiration time as a timeout token = null; } // If the tenantId passed in token options is different to the one we have // Or if we are in claim challenge and the token was rejected and a new access token need to be issued, we need to // refresh the token with the new tenantId or token. const mustRefresh = tenantIdChanged || hasClaimChallenge || cycler.mustRefresh; if (mustRefresh) { return refresh(scopes, tokenOptions); } if (cycler.shouldRefresh) { refresh(scopes, tokenOptions); } return token; }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the bearerTokenAuthenticationPolicy. */ const bearerTokenAuthenticationPolicyName = "bearerTokenAuthenticationPolicy"; /** * Try to send the given request. * * When a response is received, returns a tuple of the response received and, if the response was received * inside a thrown RestError, the RestError that was thrown. * * Otherwise, if an error was thrown while sending the request that did not provide an underlying response, it * will be rethrown. */ async function trySendRequest(request, next) { try { return [await next(request), undefined]; } catch (e) { if (isRestError(e) && e.response) { return [e.response, e]; } else { throw e; } } } /** * Default authorize request handler */ async function defaultAuthorizeRequest(options) { const { scopes, getAccessToken, request } = options; // Enable CAE true by default const getTokenOptions = { abortSignal: request.abortSignal, tracingOptions: request.tracingOptions, enableCae: true, }; const accessToken = await getAccessToken(scopes, getTokenOptions); if (accessToken) { options.request.headers.set("Authorization", `Bearer ${accessToken.token}`); } } /** * We will retrieve the challenge only if the response status code was 401, * and if the response contained the header "WWW-Authenticate" with a non-empty value. */ function isChallengeResponse(response) { return response.status === 401 && response.headers.has("WWW-Authenticate"); } /** * Re-authorize the request for CAE challenge. * The response containing the challenge is `options.response`. * If this method returns true, the underlying request will be sent once again. */ async function authorizeRequestOnCaeChallenge(onChallengeOptions, caeClaims) { const { scopes } = onChallengeOptions; const accessToken = await onChallengeOptions.getAccessToken(scopes, { enableCae: true, claims: caeClaims, }); if (!accessToken) { return false; } onChallengeOptions.request.headers.set("Authorization", `${accessToken.tokenType ?? "Bearer"} ${accessToken.token}`); return true; } /** * A policy that can request a token from a TokenCredential implementation and * then apply it to the Authorization header of a request as a Bearer token. */ function bearerTokenAuthenticationPolicy(options) { const { credential, scopes, challengeCallbacks } = options; const logger = options.logger || logger$3; const callbacks = { authorizeRequest: challengeCallbacks?.authorizeRequest?.bind(challengeCallbacks) ?? defaultAuthorizeRequest, authorizeRequestOnChallenge: challengeCallbacks?.authorizeRequestOnChallenge?.bind(challengeCallbacks), }; // This function encapsulates the entire process of reliably retrieving the token // The options are left out of the public API until there's demand to configure this. // Remember to extend `BearerTokenAuthenticationPolicyOptions` with `TokenCyclerOptions` // in order to pass through the `options` object. const getAccessToken = credential ? createTokenCycler(credential /* , options */) : () => Promise.resolve(null); return { name: bearerTokenAuthenticationPolicyName, /** * If there's no challenge parameter: * - It will try to retrieve the token using the cache, or the credential's getToken. * - Then it will try the next policy with or without the retrieved token. * * It uses the challenge parameters to: * - Skip a first attempt to get the token from the credential if there's no cached token, * since it expects the token to be retrievable only after the challenge. * - Prepare the outgoing request if the `prepareRequest` method has been provided. * - Send an initial request to receive the challenge if it fails. * - Process a challenge if the response contains it. * - Retrieve a token with the challenge information, then re-send the request. */ async sendRequest(request, next) { if (!request.url.toLowerCase().startsWith("https://")) { throw new Error("Bearer token authentication is not permitted for non-TLS protected (non-https) URLs."); } await callbacks.authorizeRequest({ scopes: Array.isArray(scopes) ? scopes : [scopes], request, getAccessToken, logger, }); let response; let error; let shouldSendRequest; [response, error] = await trySendRequest(request, next); if (isChallengeResponse(response)) { let claims = getCaeChallengeClaims(response.headers.get("WWW-Authenticate")); // Handle CAE by default when receive CAE claim if (claims) { let parsedClaim; // Return the response immediately if claims is not a valid base64 encoded string try { parsedClaim = atob(claims); } catch (e) { logger.warning(`The WWW-Authenticate header contains "claims" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`); return response; } shouldSendRequest = await authorizeRequestOnCaeChallenge({ scopes: Array.isArray(scopes) ? scopes : [scopes], response, request, getAccessToken, logger, }, parsedClaim); // Send updated request and handle response for RestError if (shouldSendRequest) { [response, error] = await trySendRequest(request, next); } } else if (callbacks.authorizeRequestOnChallenge) { // Handle custom challenges when client provides custom callback shouldSendRequest = await callbacks.authorizeRequestOnChallenge({ scopes: Array.isArray(scopes) ? scopes : [scopes], request, response, getAccessToken, logger, }); // Send updated request and handle response for RestError if (shouldSendRequest) { [response, error] = await trySendRequest(request, next); } // If we get another CAE Claim, we will handle it by default and return whatever value we receive for this if (isChallengeResponse(response)) { claims = getCaeChallengeClaims(response.headers.get("WWW-Authenticate") ?? ""); if (claims) { let parsedClaim; try { parsedClaim = atob(claims); } catch (e) { logger.warning(`The WWW-Authenticate header contains "claims" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`); return response; } shouldSendRequest = await authorizeRequestOnCaeChallenge({ scopes: Array.isArray(scopes) ? scopes : [scopes], response, request, getAccessToken, logger, }, parsedClaim); // Send updated request and handle response for RestError if (shouldSendRequest) { [response, error] = await trySendRequest(request, next); } } } } } if (error) { throw error; } else { return response; } }, }; } /** * Converts: `Bearer a="b", c="d", Pop e="f", g="h"`. * Into: `[ { scheme: 'Bearer', params: { a: 'b', c: 'd' } }, { scheme: 'Pop', params: { e: 'f', g: 'h' } } ]`. * * @internal */ function parseChallenges(challenges) { // Challenge regex seperates the string to individual challenges with different schemes in the format `Scheme a="b", c=d` // The challenge regex captures parameteres with either quotes values or unquoted values const challengeRegex = /(\w+)\s+((?:\w+=(?:"[^"]*"|[^,]*),?\s*)+)/g; // Parameter regex captures the claims group removed from the scheme in the format `a="b"` and `c="d"` // CAE challenge always have quoted parameters. For more reference, https://learn.microsoft.com/entra/identity-platform/claims-challenge const paramRegex = /(\w+)="([^"]*)"/g; const parsedChallenges = []; let match; // Iterate over each challenge match while ((match = challengeRegex.exec(challenges)) !== null) { const scheme = match[1]; const paramsString = match[2]; const params = {}; let paramMatch; // Iterate over each parameter match while ((paramMatch = paramRegex.exec(paramsString)) !== null) { params[paramMatch[1]] = paramMatch[2]; } parsedChallenges.push({ scheme, params }); } return parsedChallenges; } /** * Parse a pipeline response and look for a CAE challenge with "Bearer" scheme * Return the value in the header without parsing the challenge * @internal */ function getCaeChallengeClaims(challenges) { if (!challenges) { return; } // Find all challenges present in the header const parsedChallenges = parseChallenges(challenges); return parsedChallenges.find((x) => x.scheme === "Bearer" && x.params.claims && x.params.error === "insufficient_claims")?.params.claims; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * @internal * @param accessToken - Access token * @returns Whether a token is bearer type or not */ /** * Tests an object to determine whether it implements TokenCredential. * * @param credential - The assumed TokenCredential to be tested. */ function isTokenCredential(credential) { // Check for an object with a 'getToken' function and possibly with // a 'signRequest' function. We do this check to make sure that // a ServiceClientCredentials implementor (like TokenClientCredentials // in ms-rest-nodeauth) doesn't get mistaken for a TokenCredential if // it doesn't actually implement TokenCredential also. const castCredential = credential; return (castCredential && typeof castCredential.getToken === "function" && (castCredential.signRequest === undefined || castCredential.getToken.length > 0)); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const disableKeepAlivePolicyName = "DisableKeepAlivePolicy"; function createDisableKeepAlivePolicy() { return { name: disableKeepAlivePolicyName, async sendRequest(request, next) { request.disableKeepAlive = true; return next(request); }, }; } /** * @internal */ function pipelineContainsDisableKeepAlivePolicy(pipeline) { return pipeline.getOrderedPolicies().some((policy) => policy.name === disableKeepAlivePolicyName); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Encodes a byte array in base64 format. * @param value - the Uint8Array to encode * @internal */ function encodeByteArray(value) { return uint8ArrayToString(value, "base64"); } /** * Decodes a base64 string into a byte array. * @param value - the base64 string to decode * @internal */ function decodeString(value) { return stringToUint8Array(value, "base64"); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Default key used to access the XML attributes. */ const XML_ATTRKEY$1 = "$"; /** * Default key used to access the XML value content. */ const XML_CHARKEY$1 = "_"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A type guard for a primitive response body. * @param value - Value to test * * @internal */ function isPrimitiveBody(value, mapperTypeName) { return (mapperTypeName !== "Composite" && mapperTypeName !== "Dictionary" && (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || mapperTypeName?.match(/^(Date|DateTime|DateTimeRfc1123|UnixTime|ByteArray|Base64Url)$/i) !== null || value === undefined || value === null)); } const validateISODuration = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/; /** * Returns true if the given string is in ISO 8601 format. * @param value - The value to be validated for ISO 8601 duration format. * @internal */ function isDuration(value) { return validateISODuration.test(value); } const validUuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/i; /** * Returns true if the provided uuid is valid. * * @param uuid - The uuid that needs to be validated. * * @internal */ function isValidUuid(uuid) { return validUuidRegex.test(uuid); } /** * Maps the response as follows: * - wraps the response body if needed (typically if its type is primitive). * - returns null if the combination of the headers and the body is empty. * - otherwise, returns the combination of the headers and the body. * * @param responseObject - a representation of the parsed response * @returns the response that will be returned to the user which can be null and/or wrapped * * @internal */ function handleNullableResponseAndWrappableBody(responseObject) { const combinedHeadersAndBody = { ...responseObject.headers, ...responseObject.body, }; if (responseObject.hasNullableType && Object.getOwnPropertyNames(combinedHeadersAndBody).length === 0) { return responseObject.shouldWrapBody ? { body: null } : null; } else { return responseObject.shouldWrapBody ? { ...responseObject.headers, body: responseObject.body, } : combinedHeadersAndBody; } } /** * Take a `FullOperationResponse` and turn it into a flat * response object to hand back to the consumer. * @param fullResponse - The processed response from the operation request * @param responseSpec - The response map from the OperationSpec * * @internal */ function flattenResponse(fullResponse, responseSpec) { const parsedHeaders = fullResponse.parsedHeaders; // head methods never have a body, but we return a boolean set to body property // to indicate presence/absence of the resource if (fullResponse.request.method === "HEAD") { return { ...parsedHeaders, body: fullResponse.parsedBody, }; } const bodyMapper = responseSpec && responseSpec.bodyMapper; const isNullable = Boolean(bodyMapper?.nullable); const expectedBodyTypeName = bodyMapper?.type.name; /** If the body is asked for, we look at the expected body type to handle it */ if (expectedBodyTypeName === "Stream") { return { ...parsedHeaders, blobBody: fullResponse.blobBody, readableStreamBody: fullResponse.readableStreamBody, }; } const modelProperties = (expectedBodyTypeName === "Composite" && bodyMapper.type.modelProperties) || {}; const isPageableResponse = Object.keys(modelProperties).some((k) => modelProperties[k].serializedName === ""); if (expectedBodyTypeName === "Sequence" || isPageableResponse) { const arrayResponse = fullResponse.parsedBody ?? []; for (const key of Object.keys(modelProperties)) { if (modelProperties[key].serializedName) { arrayResponse[key] = fullResponse.parsedBody?.[key]; } } if (parsedHeaders) { for (const key of Object.keys(parsedHeaders)) { arrayResponse[key] = parsedHeaders[key]; } } return isNullable && !fullResponse.parsedBody && !parsedHeaders && Object.getOwnPropertyNames(modelProperties).length === 0 ? null : arrayResponse; } return handleNullableResponseAndWrappableBody({ body: fullResponse.parsedBody, headers: parsedHeaders, hasNullableType: isNullable, shouldWrapBody: isPrimitiveBody(fullResponse.parsedBody, expectedBodyTypeName), }); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. class SerializerImpl { modelMappers; isXML; constructor(modelMappers = {}, isXML = false) { this.modelMappers = modelMappers; this.isXML = isXML; } /** * @deprecated Removing the constraints validation on client side. */ validateConstraints(mapper, value, objectName) { const failValidation = (constraintName, constraintValue) => { throw new Error(`"${objectName}" with value "${value}" should satisfy the constraint "${constraintName}": ${constraintValue}.`); }; if (mapper.constraints && value !== undefined && value !== null) { const { ExclusiveMaximum, ExclusiveMinimum, InclusiveMaximum, InclusiveMinimum, MaxItems, MaxLength, MinItems, MinLength, MultipleOf, Pattern, UniqueItems, } = mapper.constraints; if (ExclusiveMaximum !== undefined && value >= ExclusiveMaximum) { failValidation("ExclusiveMaximum", ExclusiveMaximum); } if (ExclusiveMinimum !== undefined && value <= ExclusiveMinimum) { failValidation("ExclusiveMinimum", ExclusiveMinimum); } if (InclusiveMaximum !== undefined && value > InclusiveMaximum) { failValidation("InclusiveMaximum", InclusiveMaximum); } if (InclusiveMinimum !== undefined && value < InclusiveMinimum) { failValidation("InclusiveMinimum", InclusiveMinimum); } if (MaxItems !== undefined && value.length > MaxItems) { failValidation("MaxItems", MaxItems); } if (MaxLength !== undefined && value.length > MaxLength) { failValidation("MaxLength", MaxLength); } if (MinItems !== undefined && value.length < MinItems) { failValidation("MinItems", MinItems); } if (MinLength !== undefined && value.length < MinLength) { failValidation("MinLength", MinLength); } if (MultipleOf !== undefined && value % MultipleOf !== 0) { failValidation("MultipleOf", MultipleOf); } if (Pattern) { const pattern = typeof Pattern === "string" ? new RegExp(Pattern) : Pattern; if (typeof value !== "string" || value.match(pattern) === null) { failValidation("Pattern", Pattern); } } if (UniqueItems && value.some((item, i, ar) => ar.indexOf(item) !== i)) { failValidation("UniqueItems", UniqueItems); } } } /** * Serialize the given object based on its metadata defined in the mapper * * @param mapper - The mapper which defines the metadata of the serializable object * * @param object - A valid Javascript object to be serialized * * @param objectName - Name of the serialized object * * @param options - additional options to serialization * * @returns A valid serialized Javascript object */ serialize(mapper, object, objectName, options = { xml: {} }) { const updatedOptions = { xml: { rootName: options.xml.rootName ?? "", includeRoot: options.xml.includeRoot ?? false, xmlCharKey: options.xml.xmlCharKey ?? XML_CHARKEY$1, }, }; let payload = {}; const mapperType = mapper.type.name; if (!objectName) { objectName = mapper.serializedName; } if (mapperType.match(/^Sequence$/i) !== null) { payload = []; } if (mapper.isConstant) { object = mapper.defaultValue; } // This table of allowed values should help explain // the mapper.required and mapper.nullable properties. // X means "neither undefined or null are allowed". // || required // || true | false // nullable || ========================== // true || null | undefined/null // false || X | undefined // undefined || X | undefined/null const { required, nullable } = mapper; if (required && nullable && object === undefined) { throw new Error(`${objectName} cannot be undefined.`); } if (required && !nullable && (object === undefined || object === null)) { throw new Error(`${objectName} cannot be null or undefined.`); } if (!required && nullable === false && object === null) { throw new Error(`${objectName} cannot be null.`); } if (object === undefined || object === null) { payload = object; } else { if (mapperType.match(/^any$/i) !== null) { payload = object; } else if (mapperType.match(/^(Number|String|Boolean|Object|Stream|Uuid)$/i) !== null) { payload = serializeBasicTypes(mapperType, objectName, object); } else if (mapperType.match(/^Enum$/i) !== null) { const enumMapper = mapper; payload = serializeEnumType(objectName, enumMapper.type.allowedValues, object); } else if (mapperType.match(/^(Date|DateTime|TimeSpan|DateTimeRfc1123|UnixTime)$/i) !== null) { payload = serializeDateTypes(mapperType, object, objectName); } else if (mapperType.match(/^ByteArray$/i) !== null) { payload = serializeByteArrayType(objectName, object); } else if (mapperType.match(/^Base64Url$/i) !== null) { payload = serializeBase64UrlType(objectName, object); } else if (mapperType.match(/^Sequence$/i) !== null) { payload = serializeSequenceType(this, mapper, object, objectName, Boolean(this.isXML), updatedOptions); } else if (mapperType.match(/^Dictionary$/i) !== null) { payload = serializeDictionaryType(this, mapper, object, objectName, Boolean(this.isXML), updatedOptions); } else if (mapperType.match(/^Composite$/i) !== null) { payload = serializeCompositeType(this, mapper, object, objectName, Boolean(this.isXML), updatedOptions); } } return payload; } /** * Deserialize the given object based on its metadata defined in the mapper * * @param mapper - The mapper which defines the metadata of the serializable object * * @param responseBody - A valid Javascript entity to be deserialized * * @param objectName - Name of the deserialized object * * @param options - Controls behavior of XML parser and builder. * * @returns A valid deserialized Javascript object */ deserialize(mapper, responseBody, objectName, options = { xml: {} }) { const updatedOptions = { xml: { rootName: options.xml.rootName ?? "", includeRoot: options.xml.includeRoot ?? false, xmlCharKey: options.xml.xmlCharKey ?? XML_CHARKEY$1, }, ignoreUnknownProperties: options.ignoreUnknownProperties ?? false, }; if (responseBody === undefined || responseBody === null) { if (this.isXML && mapper.type.name === "Sequence" && !mapper.xmlIsWrapped) { // Edge case for empty XML non-wrapped lists. xml2js can't distinguish // between the list being empty versus being missing, // so let's do the more user-friendly thing and return an empty list. responseBody = []; } // specifically check for undefined as default value can be a falsey value `0, "", false, null` if (mapper.defaultValue !== undefined) { responseBody = mapper.defaultValue; } return responseBody; } let payload; const mapperType = mapper.type.name; if (!objectName) { objectName = mapper.serializedName; } if (mapperType.match(/^Composite$/i) !== null) { payload = deserializeCompositeType(this, mapper, responseBody, objectName, updatedOptions); } else { if (this.isXML) { const xmlCharKey = updatedOptions.xml.xmlCharKey; /** * If the mapper specifies this as a non-composite type value but the responseBody contains * both header ("$" i.e., XML_ATTRKEY) and body ("#" i.e., XML_CHARKEY) properties, * then just reduce the responseBody value to the body ("#" i.e., XML_CHARKEY) property. */ if (responseBody[XML_ATTRKEY$1] !== undefined && responseBody[xmlCharKey] !== undefined) { responseBody = responseBody[xmlCharKey]; } } if (mapperType.match(/^Number$/i) !== null) { payload = parseFloat(responseBody); if (isNaN(payload)) { payload = responseBody; } } else if (mapperType.match(/^Boolean$/i) !== null) { if (responseBody === "true") { payload = true; } else if (responseBody === "false") { payload = false; } else { payload = responseBody; } } else if (mapperType.match(/^(String|Enum|Object|Stream|Uuid|TimeSpan|any)$/i) !== null) { payload = responseBody; } else if (mapperType.match(/^(Date|DateTime|DateTimeRfc1123)$/i) !== null) { payload = new Date(responseBody); } else if (mapperType.match(/^UnixTime$/i) !== null) { payload = unixTimeToDate(responseBody); } else if (mapperType.match(/^ByteArray$/i) !== null) { payload = decodeString(responseBody); } else if (mapperType.match(/^Base64Url$/i) !== null) { payload = base64UrlToByteArray(responseBody); } else if (mapperType.match(/^Sequence$/i) !== null) { payload = deserializeSequenceType(this, mapper, responseBody, objectName, updatedOptions); } else if (mapperType.match(/^Dictionary$/i) !== null) { payload = deserializeDictionaryType(this, mapper, responseBody, objectName, updatedOptions); } } if (mapper.isConstant) { payload = mapper.defaultValue; } return payload; } } /** * Method that creates and returns a Serializer. * @param modelMappers - Known models to map * @param isXML - If XML should be supported */ function createSerializer(modelMappers = {}, isXML = false) { return new SerializerImpl(modelMappers, isXML); } function trimEnd(str, ch) { let len = str.length; while (len - 1 >= 0 && str[len - 1] === ch) { --len; } return str.substr(0, len); } function bufferToBase64Url(buffer) { if (!buffer) { return undefined; } if (!(buffer instanceof Uint8Array)) { throw new Error(`Please provide an input of type Uint8Array for converting to Base64Url.`); } // Uint8Array to Base64. const str = encodeByteArray(buffer); // Base64 to Base64Url. return trimEnd(str, "=").replace(/\+/g, "-").replace(/\//g, "_"); } function base64UrlToByteArray(str) { if (!str) { return undefined; } if (str && typeof str.valueOf() !== "string") { throw new Error("Please provide an input of type string for converting to Uint8Array"); } // Base64Url to Base64. str = str.replace(/-/g, "+").replace(/_/g, "/"); // Base64 to Uint8Array. return decodeString(str); } function splitSerializeName(prop) { const classes = []; let partialclass = ""; if (prop) { const subwords = prop.split("."); for (const item of subwords) { if (item.charAt(item.length - 1) === "\\") { partialclass += item.substr(0, item.length - 1) + "."; } else { partialclass += item; classes.push(partialclass); partialclass = ""; } } } return classes; } function dateToUnixTime(d) { if (!d) { return undefined; } if (typeof d.valueOf() === "string") { d = new Date(d); } return Math.floor(d.getTime() / 1000); } function unixTimeToDate(n) { if (!n) { return undefined; } return new Date(n * 1000); } function serializeBasicTypes(typeName, objectName, value) { if (value !== null && value !== undefined) { if (typeName.match(/^Number$/i) !== null) { if (typeof value !== "number") { throw new Error(`${objectName} with value ${value} must be of type number.`); } } else if (typeName.match(/^String$/i) !== null) { if (typeof value.valueOf() !== "string") { throw new Error(`${objectName} with value "${value}" must be of type string.`); } } else if (typeName.match(/^Uuid$/i) !== null) { if (!(typeof value.valueOf() === "string" && isValidUuid(value))) { throw new Error(`${objectName} with value "${value}" must be of type string and a valid uuid.`); } } else if (typeName.match(/^Boolean$/i) !== null) { if (typeof value !== "boolean") { throw new Error(`${objectName} with value ${value} must be of type boolean.`); } } else if (typeName.match(/^Stream$/i) !== null) { const objectType = typeof value; if (objectType !== "string" && typeof value.pipe !== "function" && // NodeJS.ReadableStream typeof value.tee !== "function" && // browser ReadableStream !(value instanceof ArrayBuffer) && !ArrayBuffer.isView(value) && // File objects count as a type of Blob, so we want to use instanceof explicitly !((typeof Blob === "function" || typeof Blob === "object") && value instanceof Blob) && objectType !== "function") { throw new Error(`${objectName} must be a string, Blob, ArrayBuffer, ArrayBufferView, ReadableStream, or () => ReadableStream.`); } } } return value; } function serializeEnumType(objectName, allowedValues, value) { if (!allowedValues) { throw new Error(`Please provide a set of allowedValues to validate ${objectName} as an Enum Type.`); } const isPresent = allowedValues.some((item) => { if (typeof item.valueOf() === "string") { return item.toLowerCase() === value.toLowerCase(); } return item === value; }); if (!isPresent) { throw new Error(`${value} is not a valid value for ${objectName}. The valid values are: ${JSON.stringify(allowedValues)}.`); } return value; } function serializeByteArrayType(objectName, value) { if (value !== undefined && value !== null) { if (!(value instanceof Uint8Array)) { throw new Error(`${objectName} must be of type Uint8Array.`); } value = encodeByteArray(value); } return value; } function serializeBase64UrlType(objectName, value) { if (value !== undefined && value !== null) { if (!(value instanceof Uint8Array)) { throw new Error(`${objectName} must be of type Uint8Array.`); } value = bufferToBase64Url(value); } return value; } function serializeDateTypes(typeName, value, objectName) { if (value !== undefined && value !== null) { if (typeName.match(/^Date$/i) !== null) { if (!(value instanceof Date || (typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) { throw new Error(`${objectName} must be an instanceof Date or a string in ISO8601 format.`); } value = value instanceof Date ? value.toISOString().substring(0, 10) : new Date(value).toISOString().substring(0, 10); } else if (typeName.match(/^DateTime$/i) !== null) { if (!(value instanceof Date || (typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) { throw new Error(`${objectName} must be an instanceof Date or a string in ISO8601 format.`); } value = value instanceof Date ? value.toISOString() : new Date(value).toISOString(); } else if (typeName.match(/^DateTimeRfc1123$/i) !== null) { if (!(value instanceof Date || (typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) { throw new Error(`${objectName} must be an instanceof Date or a string in RFC-1123 format.`); } value = value instanceof Date ? value.toUTCString() : new Date(value).toUTCString(); } else if (typeName.match(/^UnixTime$/i) !== null) { if (!(value instanceof Date || (typeof value.valueOf() === "string" && !isNaN(Date.parse(value))))) { throw new Error(`${objectName} must be an instanceof Date or a string in RFC-1123/ISO8601 format ` + `for it to be serialized in UnixTime/Epoch format.`); } value = dateToUnixTime(value); } else if (typeName.match(/^TimeSpan$/i) !== null) { if (!isDuration(value)) { throw new Error(`${objectName} must be a string in ISO 8601 format. Instead was "${value}".`); } } } return value; } function serializeSequenceType(serializer, mapper, object, objectName, isXml, options) { if (!Array.isArray(object)) { throw new Error(`${objectName} must be of type Array.`); } let elementType = mapper.type.element; if (!elementType || typeof elementType !== "object") { throw new Error(`"element" metadata for an Array must be defined in the ` + `mapper and it must be of type "object" in ${objectName}.`); } // Quirk: Composite mappers referenced by `element` might // not have *all* properties declared (like uberParent), // so let's try to look up the full definition by name. if (elementType.type.name === "Composite" && elementType.type.className) { elementType = serializer.modelMappers[elementType.type.className] ?? elementType; } const tempArray = []; for (let i = 0; i < object.length; i++) { const serializedValue = serializer.serialize(elementType, object[i], objectName, options); if (isXml && elementType.xmlNamespace) { const xmlnsKey = elementType.xmlNamespacePrefix ? `xmlns:${elementType.xmlNamespacePrefix}` : "xmlns"; if (elementType.type.name === "Composite") { tempArray[i] = { ...serializedValue }; tempArray[i][XML_ATTRKEY$1] = { [xmlnsKey]: elementType.xmlNamespace }; } else { tempArray[i] = {}; tempArray[i][options.xml.xmlCharKey] = serializedValue; tempArray[i][XML_ATTRKEY$1] = { [xmlnsKey]: elementType.xmlNamespace }; } } else { tempArray[i] = serializedValue; } } return tempArray; } function serializeDictionaryType(serializer, mapper, object, objectName, isXml, options) { if (typeof object !== "object") { throw new Error(`${objectName} must be of type object.`); } const valueType = mapper.type.value; if (!valueType || typeof valueType !== "object") { throw new Error(`"value" metadata for a Dictionary must be defined in the ` + `mapper and it must of type "object" in ${objectName}.`); } const tempDictionary = {}; for (const key of Object.keys(object)) { const serializedValue = serializer.serialize(valueType, object[key], objectName, options); // If the element needs an XML namespace we need to add it within the $ property tempDictionary[key] = getXmlObjectValue(valueType, serializedValue, isXml, options); } // Add the namespace to the root element if needed if (isXml && mapper.xmlNamespace) { const xmlnsKey = mapper.xmlNamespacePrefix ? `xmlns:${mapper.xmlNamespacePrefix}` : "xmlns"; const result = tempDictionary; result[XML_ATTRKEY$1] = { [xmlnsKey]: mapper.xmlNamespace }; return result; } return tempDictionary; } /** * Resolves the additionalProperties property from a referenced mapper * @param serializer - the serializer containing the entire set of mappers * @param mapper - the composite mapper to resolve * @param objectName - name of the object being serialized */ function resolveAdditionalProperties(serializer, mapper, objectName) { const additionalProperties = mapper.type.additionalProperties; if (!additionalProperties && mapper.type.className) { const modelMapper = resolveReferencedMapper(serializer, mapper, objectName); return modelMapper?.type.additionalProperties; } return additionalProperties; } /** * Finds the mapper referenced by className * @param serializer - the serializer containing the entire set of mappers * @param mapper - the composite mapper to resolve * @param objectName - name of the object being serialized */ function resolveReferencedMapper(serializer, mapper, objectName) { const className = mapper.type.className; if (!className) { throw new Error(`Class name for model "${objectName}" is not provided in the mapper "${JSON.stringify(mapper, undefined, 2)}".`); } return serializer.modelMappers[className]; } /** * Resolves a composite mapper's modelProperties. * @param serializer - the serializer containing the entire set of mappers * @param mapper - the composite mapper to resolve */ function resolveModelProperties(serializer, mapper, objectName) { let modelProps = mapper.type.modelProperties; if (!modelProps) { const modelMapper = resolveReferencedMapper(serializer, mapper, objectName); if (!modelMapper) { throw new Error(`mapper() cannot be null or undefined for model "${mapper.type.className}".`); } modelProps = modelMapper?.type.modelProperties; if (!modelProps) { throw new Error(`modelProperties cannot be null or undefined in the ` + `mapper "${JSON.stringify(modelMapper)}" of type "${mapper.type.className}" for object "${objectName}".`); } } return modelProps; } function serializeCompositeType(serializer, mapper, object, objectName, isXml, options) { if (getPolymorphicDiscriminatorRecursively(serializer, mapper)) { mapper = getPolymorphicMapper(serializer, mapper, object, "clientName"); } if (object !== undefined && object !== null) { const payload = {}; const modelProps = resolveModelProperties(serializer, mapper, objectName); for (const key of Object.keys(modelProps)) { const propertyMapper = modelProps[key]; if (propertyMapper.readOnly) { continue; } let propName; let parentObject = payload; if (serializer.isXML) { if (propertyMapper.xmlIsWrapped) { propName = propertyMapper.xmlName; } else { propName = propertyMapper.xmlElementName || propertyMapper.xmlName; } } else { const paths = splitSerializeName(propertyMapper.serializedName); propName = paths.pop(); for (const pathName of paths) { const childObject = parentObject[pathName]; if ((childObject === undefined || childObject === null) && ((object[key] !== undefined && object[key] !== null) || propertyMapper.defaultValue !== undefined)) { parentObject[pathName] = {}; } parentObject = parentObject[pathName]; } } if (parentObject !== undefined && parentObject !== null) { if (isXml && mapper.xmlNamespace) { const xmlnsKey = mapper.xmlNamespacePrefix ? `xmlns:${mapper.xmlNamespacePrefix}` : "xmlns"; parentObject[XML_ATTRKEY$1] = { ...parentObject[XML_ATTRKEY$1], [xmlnsKey]: mapper.xmlNamespace, }; } const propertyObjectName = propertyMapper.serializedName !== "" ? objectName + "." + propertyMapper.serializedName : objectName; let toSerialize = object[key]; const polymorphicDiscriminator = getPolymorphicDiscriminatorRecursively(serializer, mapper); if (polymorphicDiscriminator && polymorphicDiscriminator.clientName === key && (toSerialize === undefined || toSerialize === null)) { toSerialize = mapper.serializedName; } const serializedValue = serializer.serialize(propertyMapper, toSerialize, propertyObjectName, options); if (serializedValue !== undefined && propName !== undefined && propName !== null) { const value = getXmlObjectValue(propertyMapper, serializedValue, isXml, options); if (isXml && propertyMapper.xmlIsAttribute) { // XML_ATTRKEY, i.e., $ is the key attributes are kept under in xml2js. // This keeps things simple while preventing name collision // with names in user documents. parentObject[XML_ATTRKEY$1] = parentObject[XML_ATTRKEY$1] || {}; parentObject[XML_ATTRKEY$1][propName] = serializedValue; } else if (isXml && propertyMapper.xmlIsWrapped) { parentObject[propName] = { [propertyMapper.xmlElementName]: value }; } else { parentObject[propName] = value; } } } } const additionalPropertiesMapper = resolveAdditionalProperties(serializer, mapper, objectName); if (additionalPropertiesMapper) { const propNames = Object.keys(modelProps); for (const clientPropName of Object.keys(object)) { const isAdditionalProperty = propNames.every((pn) => pn !== clientPropName); if (isAdditionalProperty) { Object.defineProperty(payload, clientPropName, { value: serializer.serialize(additionalPropertiesMapper, object[clientPropName], objectName + '["' + clientPropName + '"]', options), enumerable: true, configurable: true, writable: true, }); } } } return payload; } return object; } function getXmlObjectValue(propertyMapper, serializedValue, isXml, options) { if (!isXml || !propertyMapper.xmlNamespace) { return serializedValue; } const xmlnsKey = propertyMapper.xmlNamespacePrefix ? `xmlns:${propertyMapper.xmlNamespacePrefix}` : "xmlns"; const xmlNamespace = { [xmlnsKey]: propertyMapper.xmlNamespace }; if (["Composite"].includes(propertyMapper.type.name)) { if (serializedValue[XML_ATTRKEY$1]) { return serializedValue; } else { const result = { ...serializedValue }; result[XML_ATTRKEY$1] = xmlNamespace; return result; } } const result = {}; result[options.xml.xmlCharKey] = serializedValue; result[XML_ATTRKEY$1] = xmlNamespace; return result; } function isSpecialXmlProperty(propertyName, options) { return [XML_ATTRKEY$1, options.xml.xmlCharKey].includes(propertyName); } function deserializeCompositeType(serializer, mapper, responseBody, objectName, options) { const xmlCharKey = options.xml.xmlCharKey ?? XML_CHARKEY$1; if (getPolymorphicDiscriminatorRecursively(serializer, mapper)) { mapper = getPolymorphicMapper(serializer, mapper, responseBody, "serializedName"); } const modelProps = resolveModelProperties(serializer, mapper, objectName); let instance = {}; const handledPropertyNames = []; for (const key of Object.keys(modelProps)) { const propertyMapper = modelProps[key]; const paths = splitSerializeName(modelProps[key].serializedName); handledPropertyNames.push(paths[0]); const { serializedName, xmlName, xmlElementName } = propertyMapper; let propertyObjectName = objectName; if (serializedName !== "" && serializedName !== undefined) { propertyObjectName = objectName + "." + serializedName; } const headerCollectionPrefix = propertyMapper.headerCollectionPrefix; if (headerCollectionPrefix) { const dictionary = {}; for (const headerKey of Object.keys(responseBody)) { if (headerKey.startsWith(headerCollectionPrefix)) { dictionary[headerKey.substring(headerCollectionPrefix.length)] = serializer.deserialize(propertyMapper.type.value, responseBody[headerKey], propertyObjectName, options); } handledPropertyNames.push(headerKey); } instance[key] = dictionary; } else if (serializer.isXML) { if (propertyMapper.xmlIsAttribute && responseBody[XML_ATTRKEY$1]) { instance[key] = serializer.deserialize(propertyMapper, responseBody[XML_ATTRKEY$1][xmlName], propertyObjectName, options); } else if (propertyMapper.xmlIsMsText) { if (responseBody[xmlCharKey] !== undefined) { instance[key] = responseBody[xmlCharKey]; } else if (typeof responseBody === "string") { // The special case where xml parser parses "content" into JSON of // `{ name: "content"}` instead of `{ name: { "_": "content" }}` instance[key] = responseBody; } } else { const propertyName = xmlElementName || xmlName || serializedName; if (propertyMapper.xmlIsWrapped) { /* a list of wrapped by For the xml example below ... ... the responseBody has { Cors: { CorsRule: [{...}, {...}] } } xmlName is "Cors" and xmlElementName is"CorsRule". */ const wrapped = responseBody[xmlName]; const elementList = wrapped?.[xmlElementName] ?? []; Object.defineProperty(instance, key, { value: serializer.deserialize(propertyMapper, elementList, propertyObjectName, options), enumerable: true, configurable: true, writable: true, }); handledPropertyNames.push(xmlName); } else { const property = responseBody[propertyName]; instance[key] = serializer.deserialize(propertyMapper, property, propertyObjectName, options); handledPropertyNames.push(propertyName); } } } else { // deserialize the property if it is present in the provided responseBody instance let propertyInstance; let res = responseBody; // traversing the object step by step. let steps = 0; for (const item of paths) { if (!res) break; steps++; res = res[item]; } // only accept null when reaching the last position of object otherwise it would be undefined if (res === null && steps < paths.length) { res = undefined; } propertyInstance = res; const polymorphicDiscriminator = mapper.type.polymorphicDiscriminator; // checking that the model property name (key)(ex: "fishtype") and the // clientName of the polymorphicDiscriminator {metadata} (ex: "fishtype") // instead of the serializedName of the polymorphicDiscriminator (ex: "fish.type") // is a better approach. The generator is not consistent with escaping '\.' in the // serializedName of the property (ex: "fish\.type") that is marked as polymorphic discriminator // and the serializedName of the metadata polymorphicDiscriminator (ex: "fish.type"). However, // the clientName transformation of the polymorphicDiscriminator (ex: "fishtype") and // the transformation of model property name (ex: "fishtype") is done consistently. // Hence, it is a safer bet to rely on the clientName of the polymorphicDiscriminator. if (polymorphicDiscriminator && key === polymorphicDiscriminator.clientName && (propertyInstance === undefined || propertyInstance === null)) { propertyInstance = mapper.serializedName; } let serializedValue; // paging if (Array.isArray(responseBody[key]) && modelProps[key].serializedName === "") { propertyInstance = responseBody[key]; const arrayInstance = serializer.deserialize(propertyMapper, propertyInstance, propertyObjectName, options); // Copy over any properties that have already been added into the instance, where they do // not exist on the newly de-serialized array for (const [k, v] of Object.entries(instance)) { if (!Object.prototype.hasOwnProperty.call(arrayInstance, k)) { arrayInstance[k] = v; } } instance = arrayInstance; } else if (propertyInstance !== undefined || propertyMapper.defaultValue !== undefined) { serializedValue = serializer.deserialize(propertyMapper, propertyInstance, propertyObjectName, options); instance[key] = serializedValue; } } } const additionalPropertiesMapper = mapper.type.additionalProperties; if (additionalPropertiesMapper) { const isAdditionalProperty = (responsePropName) => { for (const clientPropName of Object.keys(modelProps)) { const paths = splitSerializeName(modelProps[clientPropName].serializedName); if (paths[0] === responsePropName) { return false; } } return true; }; for (const responsePropName of Object.keys(responseBody)) { if (isAdditionalProperty(responsePropName)) { const deserializedValue = serializer.deserialize(additionalPropertiesMapper, responseBody[responsePropName], objectName + '["' + responsePropName + '"]', options); Object.defineProperty(instance, responsePropName, { value: deserializedValue, enumerable: true, configurable: true, writable: true, }); } } } else if (responseBody && !options.ignoreUnknownProperties) { for (const key of Object.keys(responseBody)) { if (instance[key] === undefined && !handledPropertyNames.includes(key) && !isSpecialXmlProperty(key, options)) { Object.defineProperty(instance, key, { value: responseBody[key], enumerable: true, configurable: true, writable: true, }); } } } return instance; } function deserializeDictionaryType(serializer, mapper, responseBody, objectName, options) { /* jshint validthis: true */ const value = mapper.type.value; if (!value || typeof value !== "object") { throw new Error(`"value" metadata for a Dictionary must be defined in the ` + `mapper and it must of type "object" in ${objectName}`); } if (responseBody) { const tempDictionary = {}; for (const key of Object.keys(responseBody)) { tempDictionary[key] = serializer.deserialize(value, responseBody[key], objectName, options); } return tempDictionary; } return responseBody; } function deserializeSequenceType(serializer, mapper, responseBody, objectName, options) { let element = mapper.type.element; if (!element || typeof element !== "object") { throw new Error(`"element" metadata for an Array must be defined in the ` + `mapper and it must be of type "object" in ${objectName}`); } if (responseBody) { if (!Array.isArray(responseBody)) { // xml2js will interpret a single element array as just the element, so force it to be an array responseBody = [responseBody]; } // Quirk: Composite mappers referenced by `element` might // not have *all* properties declared (like uberParent), // so let's try to look up the full definition by name. if (element.type.name === "Composite" && element.type.className) { element = serializer.modelMappers[element.type.className] ?? element; } const tempArray = []; for (let i = 0; i < responseBody.length; i++) { tempArray[i] = serializer.deserialize(element, responseBody[i], `${objectName}[${i}]`, options); } return tempArray; } return responseBody; } function getIndexDiscriminator(discriminators, discriminatorValue, typeName) { const typeNamesToCheck = [typeName]; while (typeNamesToCheck.length) { const currentName = typeNamesToCheck.shift(); const indexDiscriminator = discriminatorValue === currentName ? discriminatorValue : currentName + "." + discriminatorValue; if (Object.prototype.hasOwnProperty.call(discriminators, indexDiscriminator)) { return discriminators[indexDiscriminator]; } else { for (const [name, mapper] of Object.entries(discriminators)) { if (name.startsWith(currentName + ".") && mapper.type.uberParent === currentName && mapper.type.className) { typeNamesToCheck.push(mapper.type.className); } } } } return undefined; } function getPolymorphicMapper(serializer, mapper, object, polymorphicPropertyName) { const polymorphicDiscriminator = getPolymorphicDiscriminatorRecursively(serializer, mapper); if (polymorphicDiscriminator) { let discriminatorName = polymorphicDiscriminator[polymorphicPropertyName]; if (discriminatorName) { // The serializedName might have \\, which we just want to ignore if (polymorphicPropertyName === "serializedName") { discriminatorName = discriminatorName.replace(/\\/gi, ""); } const discriminatorValue = object[discriminatorName]; const typeName = mapper.type.uberParent ?? mapper.type.className; if (typeof discriminatorValue === "string" && typeName) { const polymorphicMapper = getIndexDiscriminator(serializer.modelMappers.discriminators, discriminatorValue, typeName); if (polymorphicMapper) { mapper = polymorphicMapper; } } } } return mapper; } function getPolymorphicDiscriminatorRecursively(serializer, mapper) { return (mapper.type.polymorphicDiscriminator || getPolymorphicDiscriminatorSafely(serializer, mapper.type.uberParent) || getPolymorphicDiscriminatorSafely(serializer, mapper.type.className)); } function getPolymorphicDiscriminatorSafely(serializer, typeName) { return (typeName && serializer.modelMappers[typeName] && serializer.modelMappers[typeName].type.polymorphicDiscriminator); } /** * Known types of Mappers */ const MapperTypeNames = { Base64Url: "Base64Url", Boolean: "Boolean", ByteArray: "ByteArray", Composite: "Composite", Date: "Date", DateTime: "DateTime", DateTimeRfc1123: "DateTimeRfc1123", Dictionary: "Dictionary", Enum: "Enum", Number: "Number", Object: "Object", Sequence: "Sequence", String: "String", Stream: "Stream", TimeSpan: "TimeSpan", UnixTime: "UnixTime", }; var stateCjsExports = requireStateCjs(); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // @ts-expect-error The recommended approach to sharing module state between ESM and CJS. // See https://github.com/isaacs/tshy/blob/main/README.md#module-local-state for additional information. /** * Defines the shared state between CJS and ESM by re-exporting the CJS state. */ const state = stateCjsExports.state; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * @internal * Retrieves the value to use for a given operation argument * @param operationArguments - The arguments passed from the generated client * @param parameter - The parameter description * @param fallbackObject - If something isn't found in the arguments bag, look here. * Generally used to look at the service client properties. */ function getOperationArgumentValueFromParameter(operationArguments, parameter, fallbackObject) { let parameterPath = parameter.parameterPath; const parameterMapper = parameter.mapper; let value; if (typeof parameterPath === "string") { parameterPath = [parameterPath]; } if (Array.isArray(parameterPath)) { if (parameterPath.length > 0) { if (parameterMapper.isConstant) { value = parameterMapper.defaultValue; } else { let propertySearchResult = getPropertyFromParameterPath(operationArguments, parameterPath); if (!propertySearchResult.propertyFound && fallbackObject) { propertySearchResult = getPropertyFromParameterPath(fallbackObject, parameterPath); } let useDefaultValue = false; if (!propertySearchResult.propertyFound) { useDefaultValue = parameterMapper.required || (parameterPath[0] === "options" && parameterPath.length === 2); } value = useDefaultValue ? parameterMapper.defaultValue : propertySearchResult.propertyValue; } } } else { if (parameterMapper.required) { value = {}; } for (const [propertyName, propertyPath] of Object.entries(parameterPath)) { const propertyMapper = parameterMapper.type.modelProperties[propertyName]; const propertyValue = getOperationArgumentValueFromParameter(operationArguments, { parameterPath: propertyPath, mapper: propertyMapper, }, fallbackObject); if (propertyValue !== undefined) { if (!value) { value = {}; } Object.defineProperty(value, propertyName, { value: propertyValue, enumerable: true, configurable: true, writable: true, }); } } } return value; } function getPropertyFromParameterPath(parent, parameterPath) { const result = { propertyFound: false }; let i = 0; for (; i < parameterPath.length; ++i) { const parameterPathPart = parameterPath[i]; // Make sure to check inherited properties too, so don't use hasOwnProperty(). if (parent && parameterPathPart in parent) { parent = parent[parameterPathPart]; } else { break; } } if (i === parameterPath.length) { result.propertyValue = parent; result.propertyFound = true; } return result; } const originalRequestSymbol$1 = Symbol.for("@azure/core-client original request"); function hasOriginalRequest(request) { return originalRequestSymbol$1 in request; } function getOperationRequestInfo(request) { if (hasOriginalRequest(request)) { return getOperationRequestInfo(request[originalRequestSymbol$1]); } let info = state.operationRequestMap.get(request); if (!info) { info = {}; state.operationRequestMap.set(request, info); } return info; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const defaultJsonContentTypes = ["application/json", "text/json"]; const defaultXmlContentTypes = ["application/xml", "application/atom+xml"]; /** * The programmatic identifier of the deserializationPolicy. */ const deserializationPolicyName = "deserializationPolicy"; /** * This policy handles parsing out responses according to OperationSpecs on the request. */ function deserializationPolicy(options = {}) { const jsonContentTypes = options.expectedContentTypes?.json ?? defaultJsonContentTypes; const xmlContentTypes = options.expectedContentTypes?.xml ?? defaultXmlContentTypes; const parseXML = options.parseXML; const serializerOptions = options.serializerOptions; const updatedOptions = { xml: { rootName: serializerOptions?.xml.rootName ?? "", includeRoot: serializerOptions?.xml.includeRoot ?? false, xmlCharKey: serializerOptions?.xml.xmlCharKey ?? XML_CHARKEY$1, }, }; return { name: deserializationPolicyName, async sendRequest(request, next) { const response = await next(request); return deserializeResponseBody(jsonContentTypes, xmlContentTypes, response, updatedOptions, parseXML); }, }; } function getOperationResponseMap(parsedResponse) { let result; const request = parsedResponse.request; const operationInfo = getOperationRequestInfo(request); const operationSpec = operationInfo?.operationSpec; if (operationSpec) { if (!operationInfo?.operationResponseGetter) { result = operationSpec.responses[parsedResponse.status]; } else { result = operationInfo?.operationResponseGetter(operationSpec, parsedResponse); } } return result; } function shouldDeserializeResponse(parsedResponse) { const request = parsedResponse.request; const operationInfo = getOperationRequestInfo(request); const shouldDeserialize = operationInfo?.shouldDeserialize; let result; if (shouldDeserialize === undefined) { result = true; } else if (typeof shouldDeserialize === "boolean") { result = shouldDeserialize; } else { result = shouldDeserialize(parsedResponse); } return result; } async function deserializeResponseBody(jsonContentTypes, xmlContentTypes, response, options, parseXML) { const parsedResponse = await parse(jsonContentTypes, xmlContentTypes, response, options, parseXML); if (!shouldDeserializeResponse(parsedResponse)) { return parsedResponse; } const operationInfo = getOperationRequestInfo(parsedResponse.request); const operationSpec = operationInfo?.operationSpec; if (!operationSpec || !operationSpec.responses) { return parsedResponse; } const responseSpec = getOperationResponseMap(parsedResponse); const { error, shouldReturnResponse } = handleErrorResponse(parsedResponse, operationSpec, responseSpec, options); if (error) { throw error; } else if (shouldReturnResponse) { return parsedResponse; } // An operation response spec does exist for current status code, so // use it to deserialize the response. if (responseSpec) { if (responseSpec.bodyMapper) { let valueToDeserialize = parsedResponse.parsedBody; if (operationSpec.isXML && responseSpec.bodyMapper.type.name === MapperTypeNames.Sequence) { valueToDeserialize = typeof valueToDeserialize === "object" ? valueToDeserialize[responseSpec.bodyMapper.xmlElementName] : []; } try { parsedResponse.parsedBody = operationSpec.serializer.deserialize(responseSpec.bodyMapper, valueToDeserialize, "operationRes.parsedBody", options); } catch (deserializeError) { const restError = new RestError(`Error ${deserializeError} occurred in deserializing the responseBody - ${parsedResponse.bodyAsText}`, { statusCode: parsedResponse.status, request: parsedResponse.request, response: parsedResponse, }); throw restError; } } else if (operationSpec.httpMethod === "HEAD") { // head methods never have a body, but we return a boolean to indicate presence/absence of the resource parsedResponse.parsedBody = response.status >= 200 && response.status < 300; } if (responseSpec.headersMapper) { parsedResponse.parsedHeaders = operationSpec.serializer.deserialize(responseSpec.headersMapper, parsedResponse.headers.toJSON(), "operationRes.parsedHeaders", { xml: {}, ignoreUnknownProperties: true }); } } return parsedResponse; } function isOperationSpecEmpty(operationSpec) { const expectedStatusCodes = Object.keys(operationSpec.responses); return (expectedStatusCodes.length === 0 || (expectedStatusCodes.length === 1 && expectedStatusCodes[0] === "default")); } function handleErrorResponse(parsedResponse, operationSpec, responseSpec, options) { const isSuccessByStatus = 200 <= parsedResponse.status && parsedResponse.status < 300; const isExpectedStatusCode = isOperationSpecEmpty(operationSpec) ? isSuccessByStatus : !!responseSpec; if (isExpectedStatusCode) { if (responseSpec) { if (!responseSpec.isError) { return { error: null, shouldReturnResponse: false }; } } else { return { error: null, shouldReturnResponse: false }; } } const errorResponseSpec = responseSpec ?? operationSpec.responses.default; const initialErrorMessage = parsedResponse.request.streamResponseStatusCodes?.has(parsedResponse.status) ? `Unexpected status code: ${parsedResponse.status}` : parsedResponse.bodyAsText; const error = new RestError(initialErrorMessage, { statusCode: parsedResponse.status, request: parsedResponse.request, response: parsedResponse, }); // If the item failed but there's no error spec or default spec to deserialize the error, // and the parsed body doesn't look like an error object, // we should fail so we just throw the parsed response if (!errorResponseSpec && !(parsedResponse.parsedBody?.error?.code && parsedResponse.parsedBody?.error?.message)) { throw error; } const defaultBodyMapper = errorResponseSpec?.bodyMapper; const defaultHeadersMapper = errorResponseSpec?.headersMapper; try { // If error response has a body, try to deserialize it using default body mapper. // Then try to extract error code & message from it if (parsedResponse.parsedBody) { const parsedBody = parsedResponse.parsedBody; let deserializedError; if (defaultBodyMapper) { let valueToDeserialize = parsedBody; if (operationSpec.isXML && defaultBodyMapper.type.name === MapperTypeNames.Sequence) { valueToDeserialize = []; const elementName = defaultBodyMapper.xmlElementName; if (typeof parsedBody === "object" && elementName) { valueToDeserialize = parsedBody[elementName]; } } deserializedError = operationSpec.serializer.deserialize(defaultBodyMapper, valueToDeserialize, "error.response.parsedBody", options); } const internalError = parsedBody.error || deserializedError || parsedBody; error.code = internalError.code; if (internalError.message) { error.message = internalError.message; } if (defaultBodyMapper) { error.response.parsedBody = deserializedError; } } // If error response has headers, try to deserialize it using default header mapper if (parsedResponse.headers && defaultHeadersMapper) { error.response.parsedHeaders = operationSpec.serializer.deserialize(defaultHeadersMapper, parsedResponse.headers.toJSON(), "operationRes.parsedHeaders"); } } catch (defaultError) { error.message = `Error "${defaultError.message}" occurred in deserializing the responseBody - "${parsedResponse.bodyAsText}" for the default response.`; } return { error, shouldReturnResponse: false }; } async function parse(jsonContentTypes, xmlContentTypes, operationResponse, opts, parseXML) { if (!operationResponse.request.streamResponseStatusCodes?.has(operationResponse.status) && operationResponse.bodyAsText) { const text = operationResponse.bodyAsText; const contentType = operationResponse.headers.get("Content-Type") || ""; const contentComponents = !contentType ? [] : contentType.split(";").map((component) => component.toLowerCase()); try { if (contentComponents.length === 0 || contentComponents.some((component) => jsonContentTypes.indexOf(component) !== -1)) { operationResponse.parsedBody = JSON.parse(text); return operationResponse; } else if (contentComponents.some((component) => xmlContentTypes.indexOf(component) !== -1)) { if (!parseXML) { throw new Error("Parsing XML not supported."); } const body = await parseXML(text, opts.xml); operationResponse.parsedBody = body; return operationResponse; } } catch (err) { const msg = `Error "${err}" occurred while parsing the response body - ${operationResponse.bodyAsText}.`; const errCode = err.code || RestError.PARSE_ERROR; const e = new RestError(msg, { code: errCode, statusCode: operationResponse.status, request: operationResponse.request, response: operationResponse, }); throw e; } } return operationResponse; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Gets the list of status codes for streaming responses. * @internal */ function getStreamingResponseStatusCodes(operationSpec) { const result = new Set(); for (const [statusCode, operationResponse] of Object.entries(operationSpec.responses)) { if (operationResponse.bodyMapper && operationResponse.bodyMapper.type.name === MapperTypeNames.Stream) { result.add(Number(statusCode)); } } return result; } /** * Get the path to this parameter's value as a dotted string (a.b.c). * @param parameter - The parameter to get the path string for. * @returns The path to this parameter's value as a dotted string. * @internal */ function getPathStringFromParameter(parameter) { const { parameterPath, mapper } = parameter; let result; if (typeof parameterPath === "string") { result = parameterPath; } else if (Array.isArray(parameterPath)) { result = parameterPath.join("."); } else { result = mapper.serializedName; } return result; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the serializationPolicy. */ const serializationPolicyName = "serializationPolicy"; /** * This policy handles assembling the request body and headers using * an OperationSpec and OperationArguments on the request. */ function serializationPolicy(options = {}) { const stringifyXML = options.stringifyXML; return { name: serializationPolicyName, sendRequest(request, next) { const operationInfo = getOperationRequestInfo(request); const operationSpec = operationInfo?.operationSpec; const operationArguments = operationInfo?.operationArguments; if (operationSpec && operationArguments) { serializeHeaders(request, operationArguments, operationSpec); serializeRequestBody(request, operationArguments, operationSpec, stringifyXML); } return next(request); }, }; } /** * @internal */ function serializeHeaders(request, operationArguments, operationSpec) { if (operationSpec.headerParameters) { for (const headerParameter of operationSpec.headerParameters) { let headerValue = getOperationArgumentValueFromParameter(operationArguments, headerParameter); if ((headerValue !== null && headerValue !== undefined) || headerParameter.mapper.required) { headerValue = operationSpec.serializer.serialize(headerParameter.mapper, headerValue, getPathStringFromParameter(headerParameter)); const headerCollectionPrefix = headerParameter.mapper .headerCollectionPrefix; if (headerCollectionPrefix) { for (const key of Object.keys(headerValue)) { request.headers.set(headerCollectionPrefix + key, headerValue[key]); } } else { request.headers.set(headerParameter.mapper.serializedName || getPathStringFromParameter(headerParameter), headerValue); } } } } const customHeaders = operationArguments.options?.requestOptions?.customHeaders; if (customHeaders) { for (const customHeaderName of Object.keys(customHeaders)) { request.headers.set(customHeaderName, customHeaders[customHeaderName]); } } } /** * @internal */ function serializeRequestBody(request, operationArguments, operationSpec, stringifyXML = function () { throw new Error("XML serialization unsupported!"); }) { const serializerOptions = operationArguments.options?.serializerOptions; const updatedOptions = { xml: { rootName: serializerOptions?.xml.rootName ?? "", includeRoot: serializerOptions?.xml.includeRoot ?? false, xmlCharKey: serializerOptions?.xml.xmlCharKey ?? XML_CHARKEY$1, }, }; const xmlCharKey = updatedOptions.xml.xmlCharKey; if (operationSpec.requestBody && operationSpec.requestBody.mapper) { request.body = getOperationArgumentValueFromParameter(operationArguments, operationSpec.requestBody); const bodyMapper = operationSpec.requestBody.mapper; const { required, serializedName, xmlName, xmlElementName, xmlNamespace, xmlNamespacePrefix, nullable, } = bodyMapper; const typeName = bodyMapper.type.name; try { if ((request.body !== undefined && request.body !== null) || (nullable && request.body === null) || required) { const requestBodyParameterPathString = getPathStringFromParameter(operationSpec.requestBody); request.body = operationSpec.serializer.serialize(bodyMapper, request.body, requestBodyParameterPathString, updatedOptions); const isStream = typeName === MapperTypeNames.Stream; if (operationSpec.isXML) { const xmlnsKey = xmlNamespacePrefix ? `xmlns:${xmlNamespacePrefix}` : "xmlns"; const value = getXmlValueWithNamespace(xmlNamespace, xmlnsKey, typeName, request.body, updatedOptions); if (typeName === MapperTypeNames.Sequence) { request.body = stringifyXML(prepareXMLRootList(value, xmlElementName || xmlName || serializedName, xmlnsKey, xmlNamespace), { rootName: xmlName || serializedName, xmlCharKey }); } else if (!isStream) { request.body = stringifyXML(value, { rootName: xmlName || serializedName, xmlCharKey, }); } } else if (typeName === MapperTypeNames.String && (operationSpec.contentType?.match("text/plain") || operationSpec.mediaType === "text")) { // the String serializer has validated that request body is a string // so just send the string. return; } else if (!isStream) { request.body = JSON.stringify(request.body); } } } catch (error) { throw new Error(`Error "${error.message}" occurred in serializing the payload - ${JSON.stringify(serializedName, undefined, " ")}.`); } } else if (operationSpec.formDataParameters && operationSpec.formDataParameters.length > 0) { request.formData = {}; for (const formDataParameter of operationSpec.formDataParameters) { const formDataParameterValue = getOperationArgumentValueFromParameter(operationArguments, formDataParameter); if (formDataParameterValue !== undefined && formDataParameterValue !== null) { const formDataParameterPropertyName = formDataParameter.mapper.serializedName || getPathStringFromParameter(formDataParameter); request.formData[formDataParameterPropertyName] = operationSpec.serializer.serialize(formDataParameter.mapper, formDataParameterValue, getPathStringFromParameter(formDataParameter), updatedOptions); } } } } /** * Adds an xml namespace to the xml serialized object if needed, otherwise it just returns the value itself */ function getXmlValueWithNamespace(xmlNamespace, xmlnsKey, typeName, serializedValue, options) { // Composite and Sequence schemas already got their root namespace set during serialization // We just need to add xmlns to the other schema types if (xmlNamespace && !["Composite", "Sequence", "Dictionary"].includes(typeName)) { const result = {}; result[options.xml.xmlCharKey] = serializedValue; result[XML_ATTRKEY$1] = { [xmlnsKey]: xmlNamespace }; return result; } return serializedValue; } function prepareXMLRootList(obj, elementName, xmlNamespaceKey, xmlNamespace) { if (!Array.isArray(obj)) { obj = [obj]; } if (!xmlNamespaceKey || !xmlNamespace) { return { [elementName]: obj }; } const result = { [elementName]: obj }; result[XML_ATTRKEY$1] = { [xmlNamespaceKey]: xmlNamespace }; return result; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Creates a new Pipeline for use with a Service Client. * Adds in deserializationPolicy by default. * Also adds in bearerTokenAuthenticationPolicy if passed a TokenCredential. * @param options - Options to customize the created pipeline. */ function createClientPipeline(options = {}) { const pipeline = createPipelineFromOptions(options ?? {}); if (options.credentialOptions) { pipeline.addPolicy(bearerTokenAuthenticationPolicy({ credential: options.credentialOptions.credential, scopes: options.credentialOptions.credentialScopes, })); } pipeline.addPolicy(serializationPolicy(options.serializationOptions), { phase: "Serialize" }); pipeline.addPolicy(deserializationPolicy(options.deserializationOptions), { phase: "Deserialize", }); return pipeline; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. let cachedHttpClient; function getCachedDefaultHttpClient$1() { if (!cachedHttpClient) { cachedHttpClient = createDefaultHttpClient(); } return cachedHttpClient; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const CollectionFormatToDelimiterMap = { CSV: ",", SSV: " ", Multi: "Multi", TSV: "\t", Pipes: "|", }; function getRequestUrl(baseUri, operationSpec, operationArguments, fallbackObject) { const urlReplacements = calculateUrlReplacements(operationSpec, operationArguments, fallbackObject); let isAbsolutePath = false; let requestUrl = replaceAll(baseUri, urlReplacements); if (operationSpec.path) { let path = replaceAll(operationSpec.path, urlReplacements); // QUIRK: sometimes we get a path component like /{nextLink} // which may be a fully formed URL with a leading /. In that case, we should // remove the leading / if (operationSpec.path === "/{nextLink}" && path.startsWith("/")) { path = path.substring(1); } // QUIRK: sometimes we get a path component like {nextLink} // which may be a fully formed URL. In that case, we should // ignore the baseUri. if (isAbsoluteUrl(path)) { requestUrl = path; isAbsolutePath = true; } else { requestUrl = appendPath(requestUrl, path); } } const { queryParams, sequenceParams } = calculateQueryParameters(operationSpec, operationArguments, fallbackObject); /** * Notice that this call sets the `noOverwrite` parameter to true if the `requestUrl` * is an absolute path. This ensures that existing query parameter values in `requestUrl` * do not get overwritten. On the other hand when `requestUrl` is not absolute path, it * is still being built so there is nothing to overwrite. */ requestUrl = appendQueryParams(requestUrl, queryParams, sequenceParams, isAbsolutePath); return requestUrl; } function replaceAll(input, replacements) { let result = input; for (const [searchValue, replaceValue] of replacements) { result = result.split(searchValue).join(replaceValue); } return result; } function calculateUrlReplacements(operationSpec, operationArguments, fallbackObject) { const result = new Map(); if (operationSpec.urlParameters?.length) { for (const urlParameter of operationSpec.urlParameters) { let urlParameterValue = getOperationArgumentValueFromParameter(operationArguments, urlParameter, fallbackObject); const parameterPathString = getPathStringFromParameter(urlParameter); urlParameterValue = operationSpec.serializer.serialize(urlParameter.mapper, urlParameterValue, parameterPathString); if (!urlParameter.skipEncoding) { urlParameterValue = encodeURIComponent(urlParameterValue); } result.set(`{${urlParameter.mapper.serializedName || parameterPathString}}`, urlParameterValue); } } return result; } function isAbsoluteUrl(url) { return url.includes("://"); } function appendPath(url, pathToAppend) { if (!pathToAppend) { return url; } const parsedUrl = new URL(url); let newPath = parsedUrl.pathname; if (!newPath.endsWith("/")) { newPath = `${newPath}/`; } if (pathToAppend.startsWith("/")) { pathToAppend = pathToAppend.substring(1); } const searchStart = pathToAppend.indexOf("?"); if (searchStart !== -1) { const path = pathToAppend.substring(0, searchStart); const search = pathToAppend.substring(searchStart + 1); newPath = newPath + path; if (search) { parsedUrl.search = parsedUrl.search ? `${parsedUrl.search}&${search}` : search; } } else { newPath = newPath + pathToAppend; } // Use Object.assign to bypass react-native's incorrect readonly URL.pathname declaration Object.assign(parsedUrl, { pathname: newPath }); return parsedUrl.toString(); } function calculateQueryParameters(operationSpec, operationArguments, fallbackObject) { const result = new Map(); const sequenceParams = new Set(); if (operationSpec.queryParameters?.length) { for (const queryParameter of operationSpec.queryParameters) { if (queryParameter.mapper.type.name === "Sequence" && queryParameter.mapper.serializedName) { sequenceParams.add(queryParameter.mapper.serializedName); } let queryParameterValue = getOperationArgumentValueFromParameter(operationArguments, queryParameter, fallbackObject); if ((queryParameterValue !== undefined && queryParameterValue !== null) || queryParameter.mapper.required) { queryParameterValue = operationSpec.serializer.serialize(queryParameter.mapper, queryParameterValue, getPathStringFromParameter(queryParameter)); const delimiter = queryParameter.collectionFormat ? CollectionFormatToDelimiterMap[queryParameter.collectionFormat] : ""; if (Array.isArray(queryParameterValue)) { // replace null and undefined queryParameterValue = queryParameterValue.map((item) => { if (item === null || item === undefined) { return ""; } return item; }); } if (queryParameter.collectionFormat === "Multi" && queryParameterValue.length === 0) { continue; } else if (Array.isArray(queryParameterValue) && (queryParameter.collectionFormat === "SSV" || queryParameter.collectionFormat === "TSV")) { queryParameterValue = queryParameterValue.join(delimiter); } if (!queryParameter.skipEncoding) { if (Array.isArray(queryParameterValue)) { queryParameterValue = queryParameterValue.map((item) => { return encodeURIComponent(item); }); } else { queryParameterValue = encodeURIComponent(queryParameterValue); } } // Join pipes and CSV *after* encoding, or the server will be upset. if (Array.isArray(queryParameterValue) && (queryParameter.collectionFormat === "CSV" || queryParameter.collectionFormat === "Pipes")) { queryParameterValue = queryParameterValue.join(delimiter); } result.set(queryParameter.mapper.serializedName || getPathStringFromParameter(queryParameter), queryParameterValue); } } } return { queryParams: result, sequenceParams, }; } function simpleParseQueryParams(queryString) { const result = new Map(); if (!queryString || queryString[0] !== "?") { return result; } // remove the leading ? queryString = queryString.slice(1); const pairs = queryString.split("&"); for (const pair of pairs) { const [name, value] = pair.split("=", 2); const existingValue = result.get(name); if (existingValue) { if (Array.isArray(existingValue)) { existingValue.push(value); } else { result.set(name, [existingValue, value]); } } else { result.set(name, value); } } return result; } /** @internal */ function appendQueryParams(url, queryParams, sequenceParams, noOverwrite = false) { if (queryParams.size === 0) { return url; } const parsedUrl = new URL(url); // QUIRK: parsedUrl.searchParams will have their name/value pairs decoded, which // can change their meaning to the server, such as in the case of a SAS signature. // To avoid accidentally un-encoding a query param, we parse the key/values ourselves const combinedParams = simpleParseQueryParams(parsedUrl.search); for (const [name, value] of queryParams) { const existingValue = combinedParams.get(name); if (Array.isArray(existingValue)) { if (Array.isArray(value)) { existingValue.push(...value); const valueSet = new Set(existingValue); combinedParams.set(name, Array.from(valueSet)); } else { existingValue.push(value); } } else if (existingValue) { if (Array.isArray(value)) { value.unshift(existingValue); } else if (sequenceParams.has(name)) { combinedParams.set(name, [existingValue, value]); } if (!noOverwrite) { combinedParams.set(name, value); } } else { combinedParams.set(name, value); } } const searchPieces = []; for (const [name, value] of combinedParams) { if (typeof value === "string") { searchPieces.push(`${name}=${value}`); } else if (Array.isArray(value)) { // QUIRK: If we get an array of values, include multiple key/value pairs for (const subValue of value) { searchPieces.push(`${name}=${subValue}`); } } else { searchPieces.push(`${name}=${value}`); } } // QUIRK: we have to set search manually as searchParams will encode comma when it shouldn't. parsedUrl.search = searchPieces.length ? `?${searchPieces.join("&")}` : ""; return parsedUrl.toString(); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const logger$2 = createClientLogger("core-client"); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Initializes a new instance of the ServiceClient. */ class ServiceClient { /** * If specified, this is the base URI that requests will be made against for this ServiceClient. * If it is not specified, then all OperationSpecs must contain a baseUrl property. */ _endpoint; /** * The default request content type for the service. * Used if no requestContentType is present on an OperationSpec. */ _requestContentType; /** * Set to true if the request is sent over HTTP instead of HTTPS */ _allowInsecureConnection; /** * The HTTP client that will be used to send requests. */ _httpClient; /** * The pipeline used by this client to make requests */ pipeline; /** * The ServiceClient constructor * @param options - The service client options that govern the behavior of the client. */ constructor(options = {}) { this._requestContentType = options.requestContentType; this._endpoint = options.endpoint ?? options.baseUri; if (options.baseUri) { logger$2.warning("The baseUri option for SDK Clients has been deprecated, please use endpoint instead."); } this._allowInsecureConnection = options.allowInsecureConnection; this._httpClient = options.httpClient || getCachedDefaultHttpClient$1(); this.pipeline = options.pipeline || createDefaultPipeline(options); if (options.additionalPolicies?.length) { for (const { policy, position } of options.additionalPolicies) { // Sign happens after Retry and is commonly needed to occur // before policies that intercept post-retry. const afterPhase = position === "perRetry" ? "Sign" : undefined; this.pipeline.addPolicy(policy, { afterPhase, }); } } } /** * Send the provided httpRequest. */ sendRequest(request) { return this.pipeline.sendRequest(this._httpClient, request); } /** * Send an HTTP request that is populated using the provided OperationSpec. * @typeParam T - The typed result of the request, based on the OperationSpec. * @param operationArguments - The arguments that the HTTP request's templated values will be populated from. * @param operationSpec - The OperationSpec to use to populate the httpRequest. */ async sendOperationRequest(operationArguments, operationSpec) { const endpoint = operationSpec.baseUrl || this._endpoint; if (!endpoint) { throw new Error("If operationSpec.baseUrl is not specified, then the ServiceClient must have a endpoint string property that contains the base URL to use."); } // Templatized URLs sometimes reference properties on the ServiceClient child class, // so we have to pass `this` below in order to search these properties if they're // not part of OperationArguments const url = getRequestUrl(endpoint, operationSpec, operationArguments, this); const request = createPipelineRequest({ url, }); request.method = operationSpec.httpMethod; const operationInfo = getOperationRequestInfo(request); operationInfo.operationSpec = operationSpec; operationInfo.operationArguments = operationArguments; const contentType = operationSpec.contentType || this._requestContentType; if (contentType && operationSpec.requestBody) { request.headers.set("Content-Type", contentType); } const options = operationArguments.options; if (options) { const requestOptions = options.requestOptions; if (requestOptions) { if (requestOptions.timeout) { request.timeout = requestOptions.timeout; } if (requestOptions.onUploadProgress) { request.onUploadProgress = requestOptions.onUploadProgress; } if (requestOptions.onDownloadProgress) { request.onDownloadProgress = requestOptions.onDownloadProgress; } if (requestOptions.shouldDeserialize !== undefined) { operationInfo.shouldDeserialize = requestOptions.shouldDeserialize; } if (requestOptions.allowInsecureConnection) { request.allowInsecureConnection = true; } } if (options.abortSignal) { request.abortSignal = options.abortSignal; } if (options.tracingOptions) { request.tracingOptions = options.tracingOptions; } } if (this._allowInsecureConnection) { request.allowInsecureConnection = true; } if (request.streamResponseStatusCodes === undefined) { request.streamResponseStatusCodes = getStreamingResponseStatusCodes(operationSpec); } try { const rawResponse = await this.sendRequest(request); const flatResponse = flattenResponse(rawResponse, operationSpec.responses[rawResponse.status]); if (options?.onResponse) { options.onResponse(rawResponse, flatResponse); } return flatResponse; } catch (error) { if (typeof error === "object" && error?.response) { const rawResponse = error.response; const flatResponse = flattenResponse(rawResponse, operationSpec.responses[error.statusCode] || operationSpec.responses["default"]); error.details = flatResponse; if (options?.onResponse) { options.onResponse(rawResponse, flatResponse, error); } } throw error; } } } function createDefaultPipeline(options) { const credentialScopes = getCredentialScopes(options); const credentialOptions = options.credential && credentialScopes ? { credentialScopes, credential: options.credential } : undefined; return createClientPipeline({ ...options, credentialOptions, }); } function getCredentialScopes(options) { if (options.credentialScopes) { return options.credentialScopes; } if (options.endpoint) { return `${options.endpoint}/.default`; } if (options.baseUri) { return `${options.baseUri}/.default`; } if (options.credential) { throw new Error(`When using credentials, the ServiceClientOptions must contain either a endpoint or a credentialScopes. Unable to create a bearerTokenAuthenticationPolicy`); } return undefined; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A set of constants used internally when processing requests. */ const Constants = { DefaultScope: "/.default", /** * Defines constants for use with HTTP headers. */ HeaderConstants: { /** * The Authorization header. */ AUTHORIZATION: "authorization", }, }; function isUuid(text) { return /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/.test(text); } /** * Defines a callback to handle auth challenge for Storage APIs. * This implements the bearer challenge process described here: https://learn.microsoft.com/rest/api/storageservices/authorize-with-azure-active-directory#bearer-challenge * Handling has specific features for storage that departs to the general AAD challenge docs. **/ const authorizeRequestOnTenantChallenge = async (challengeOptions) => { const requestOptions = requestToOptions(challengeOptions.request); const challenge = getChallenge(challengeOptions.response); if (challenge) { const challengeInfo = parseChallenge(challenge); const challengeScopes = buildScopes(challengeOptions, challengeInfo); const tenantId = extractTenantId(challengeInfo); if (!tenantId) { return false; } const accessToken = await challengeOptions.getAccessToken(challengeScopes, { ...requestOptions, tenantId, }); if (!accessToken) { return false; } challengeOptions.request.headers.set(Constants.HeaderConstants.AUTHORIZATION, `${accessToken.tokenType ?? "Bearer"} ${accessToken.token}`); return true; } return false; }; /** * Extracts the tenant id from the challenge information * The tenant id is contained in the authorization_uri as the first * path part. */ function extractTenantId(challengeInfo) { const parsedAuthUri = new URL(challengeInfo.authorization_uri); const pathSegments = parsedAuthUri.pathname.split("/"); const tenantId = pathSegments[1]; if (tenantId && isUuid(tenantId)) { return tenantId; } return undefined; } /** * Builds the authentication scopes based on the information that comes in the * challenge information. Scopes url is present in the resource_id, if it is empty * we keep using the original scopes. */ function buildScopes(challengeOptions, challengeInfo) { if (!challengeInfo.resource_id) { return challengeOptions.scopes; } const challengeScopes = new URL(challengeInfo.resource_id); let scope = new URL(Constants.DefaultScope, challengeScopes.origin).toString(); if (scope === "https://disk.azure.com/.default") { // the extra slash is required by the service scope = "https://disk.azure.com//.default"; } return [scope]; } /** * We will retrieve the challenge only if the response status code was 401, * and if the response contained the header "WWW-Authenticate" with a non-empty value. */ function getChallenge(response) { const challenge = response.headers.get("WWW-Authenticate"); if (response.status === 401 && challenge) { return challenge; } return; } /** * Converts: `Bearer a="b" c="d"`. * Into: `[ { a: 'b', c: 'd' }]`. * * @internal */ function parseChallenge(challenge) { const bearerChallenge = challenge.slice("Bearer ".length); const challengeParts = `${bearerChallenge.trim()} `.split(" ").filter((x) => x); const keyValuePairs = challengeParts.map((keyValue) => (([key, value]) => ({ [key]: value }))(keyValue.trim().split("="))); // Key-value pairs to plain object: return keyValuePairs.reduce((a, b) => ({ ...a, ...b }), {}); } /** * Extracts the options form a Pipeline Request for later re-use */ function requestToOptions(request) { return { abortSignal: request.abortSignal, requestOptions: { timeout: request.timeout, }, tracingOptions: request.tracingOptions, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // We use a custom symbol to cache a reference to the original request without // exposing it on the public interface. const originalRequestSymbol = Symbol("Original PipelineRequest"); // Symbol.for() will return the same symbol if it's already been created // This particular one is used in core-client to handle the case of when a request is // cloned but we need to retrieve the OperationSpec and OperationArguments from the // original request. const originalClientRequestSymbol = Symbol.for("@azure/core-client original request"); function toPipelineRequest(webResource, options = {}) { const compatWebResource = webResource; const request = compatWebResource[originalRequestSymbol]; const headers = createHttpHeaders(webResource.headers.toJson({ preserveCase: true })); if (request) { request.headers = headers; return request; } else { const newRequest = createPipelineRequest({ url: webResource.url, method: webResource.method, headers, withCredentials: webResource.withCredentials, timeout: webResource.timeout, requestId: webResource.requestId, abortSignal: webResource.abortSignal, body: webResource.body, formData: webResource.formData, disableKeepAlive: !!webResource.keepAlive, onDownloadProgress: webResource.onDownloadProgress, onUploadProgress: webResource.onUploadProgress, proxySettings: webResource.proxySettings, streamResponseStatusCodes: webResource.streamResponseStatusCodes, agent: webResource.agent, requestOverrides: webResource.requestOverrides, }); if (options.originalRequest) { newRequest[originalClientRequestSymbol] = options.originalRequest; } return newRequest; } } function toWebResourceLike(request, options) { const originalRequest = options?.originalRequest ?? request; const webResource = { url: request.url, method: request.method, headers: toHttpHeadersLike(request.headers), withCredentials: request.withCredentials, timeout: request.timeout, requestId: request.headers.get("x-ms-client-request-id") || request.requestId, abortSignal: request.abortSignal, body: request.body, formData: request.formData, keepAlive: !!request.disableKeepAlive, onDownloadProgress: request.onDownloadProgress, onUploadProgress: request.onUploadProgress, proxySettings: request.proxySettings, streamResponseStatusCodes: request.streamResponseStatusCodes, agent: request.agent, requestOverrides: request.requestOverrides, clone() { throw new Error("Cannot clone a non-proxied WebResourceLike"); }, prepare() { throw new Error("WebResourceLike.prepare() is not supported by @azure/core-http-compat"); }, validateRequestProperties() { /** do nothing */ }, }; if (options?.createProxy) { return new Proxy(webResource, { get(target, prop, receiver) { if (prop === originalRequestSymbol) { return request; } else if (prop === "clone") { return () => { return toWebResourceLike(toPipelineRequest(webResource, { originalRequest }), { createProxy: true, originalRequest, }); }; } return Reflect.get(target, prop, receiver); }, set(target, prop, value, receiver) { if (prop === "keepAlive") { request.disableKeepAlive = !value; } const passThroughProps = [ "url", "method", "withCredentials", "timeout", "requestId", "abortSignal", "body", "formData", "onDownloadProgress", "onUploadProgress", "proxySettings", "streamResponseStatusCodes", "agent", "requestOverrides", ]; if (typeof prop === "string" && passThroughProps.includes(prop)) { request[prop] = value; } return Reflect.set(target, prop, value, receiver); }, }); } else { return webResource; } } /** * Converts HttpHeaders from core-rest-pipeline to look like * HttpHeaders from core-http. * @param headers - HttpHeaders from core-rest-pipeline * @returns HttpHeaders as they looked in core-http */ function toHttpHeadersLike(headers) { return new HttpHeaders(headers.toJSON({ preserveCase: true })); } /** * A collection of HttpHeaders that can be sent with a HTTP request. */ function getHeaderKey(headerName) { return headerName.toLowerCase(); } /** * A collection of HTTP header key/value pairs. */ class HttpHeaders { _headersMap; constructor(rawHeaders) { this._headersMap = {}; if (rawHeaders) { for (const headerName in rawHeaders) { this.set(headerName, rawHeaders[headerName]); } } } /** * Set a header in this collection with the provided name and value. The name is * case-insensitive. * @param headerName - The name of the header to set. This value is case-insensitive. * @param headerValue - The value of the header to set. */ set(headerName, headerValue) { this._headersMap[getHeaderKey(headerName)] = { name: headerName, value: headerValue.toString(), }; } /** * Get the header value for the provided header name, or undefined if no header exists in this * collection with the provided name. * @param headerName - The name of the header. */ get(headerName) { const header = this._headersMap[getHeaderKey(headerName)]; return !header ? undefined : header.value; } /** * Get whether or not this header collection contains a header entry for the provided header name. */ contains(headerName) { return !!this._headersMap[getHeaderKey(headerName)]; } /** * Remove the header with the provided headerName. Return whether or not the header existed and * was removed. * @param headerName - The name of the header to remove. */ remove(headerName) { const result = this.contains(headerName); delete this._headersMap[getHeaderKey(headerName)]; return result; } /** * Get the headers that are contained this collection as an object. */ rawHeaders() { return this.toJson({ preserveCase: true }); } /** * Get the headers that are contained in this collection as an array. */ headersArray() { const headers = []; for (const headerKey in this._headersMap) { headers.push(this._headersMap[headerKey]); } return headers; } /** * Get the header names that are contained in this collection. */ headerNames() { const headerNames = []; const headers = this.headersArray(); for (let i = 0; i < headers.length; ++i) { headerNames.push(headers[i].name); } return headerNames; } /** * Get the header values that are contained in this collection. */ headerValues() { const headerValues = []; const headers = this.headersArray(); for (let i = 0; i < headers.length; ++i) { headerValues.push(headers[i].value); } return headerValues; } /** * Get the JSON object representation of this HTTP header collection. */ toJson(options = {}) { const result = {}; if (options.preserveCase) { for (const headerKey in this._headersMap) { const header = this._headersMap[headerKey]; result[header.name] = header.value; } } else { for (const headerKey in this._headersMap) { const header = this._headersMap[headerKey]; result[getHeaderKey(header.name)] = header.value; } } return result; } /** * Get the string representation of this HTTP header collection. */ toString() { return JSON.stringify(this.toJson({ preserveCase: true })); } /** * Create a deep clone/copy of this HttpHeaders collection. */ clone() { const resultPreservingCasing = {}; for (const headerKey in this._headersMap) { const header = this._headersMap[headerKey]; resultPreservingCasing[header.name] = header.value; } return new HttpHeaders(resultPreservingCasing); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const originalResponse = Symbol("Original FullOperationResponse"); /** * A helper to convert response objects from the new pipeline back to the old one. * @param response - A response object from core-client. * @returns A response compatible with `HttpOperationResponse` from core-http. */ function toCompatResponse(response, options) { let request = toWebResourceLike(response.request); let headers = toHttpHeadersLike(response.headers); if (options?.createProxy) { return new Proxy(response, { get(target, prop, receiver) { if (prop === "headers") { return headers; } else if (prop === "request") { return request; } else if (prop === originalResponse) { return response; } return Reflect.get(target, prop, receiver); }, set(target, prop, value, receiver) { if (prop === "headers") { headers = value; } else if (prop === "request") { request = value; } return Reflect.set(target, prop, value, receiver); }, }); } else { return { ...response, request, headers, }; } } /** * A helper to convert back to a PipelineResponse * @param compatResponse - A response compatible with `HttpOperationResponse` from core-http. */ function toPipelineResponse(compatResponse) { const extendedCompatResponse = compatResponse; const response = extendedCompatResponse[originalResponse]; const headers = createHttpHeaders(compatResponse.headers.toJson({ preserveCase: true })); if (response) { response.headers = headers; return response; } else { return { ...compatResponse, headers, request: toPipelineRequest(compatResponse.request), }; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Client to provide compatability between core V1 & V2. */ class ExtendedServiceClient extends ServiceClient { constructor(options) { super(options); if (options.keepAliveOptions?.enable === false && !pipelineContainsDisableKeepAlivePolicy(this.pipeline)) { this.pipeline.addPolicy(createDisableKeepAlivePolicy()); } if (options.redirectOptions?.handleRedirects === false) { this.pipeline.removePolicy({ name: redirectPolicyName, }); } } /** * Compatible send operation request function. * * @param operationArguments - Operation arguments * @param operationSpec - Operation Spec * @returns */ async sendOperationRequest(operationArguments, operationSpec) { const userProvidedCallBack = operationArguments?.options?.onResponse; let lastResponse; function onResponse(rawResponse, flatResponse, error) { lastResponse = rawResponse; if (userProvidedCallBack) { userProvidedCallBack(rawResponse, flatResponse, error); } } operationArguments.options = { ...operationArguments.options, onResponse, }; const result = await super.sendOperationRequest(operationArguments, operationSpec); if (lastResponse) { Object.defineProperty(result, "_response", { value: toCompatResponse(lastResponse), }); } return result; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * An enum for compatibility with RequestPolicy */ var HttpPipelineLogLevel; (function (HttpPipelineLogLevel) { HttpPipelineLogLevel[HttpPipelineLogLevel["ERROR"] = 1] = "ERROR"; HttpPipelineLogLevel[HttpPipelineLogLevel["INFO"] = 3] = "INFO"; HttpPipelineLogLevel[HttpPipelineLogLevel["OFF"] = 0] = "OFF"; HttpPipelineLogLevel[HttpPipelineLogLevel["WARNING"] = 2] = "WARNING"; })(HttpPipelineLogLevel || (HttpPipelineLogLevel = {})); const mockRequestPolicyOptions = { log(_logLevel, _message) { /* do nothing */ }, shouldLog(_logLevel) { return false; }, }; /** * The name of the RequestPolicyFactoryPolicy */ const requestPolicyFactoryPolicyName = "RequestPolicyFactoryPolicy"; /** * A policy that wraps policies written for core-http. * @param factories - An array of `RequestPolicyFactory` objects from a core-http pipeline */ function createRequestPolicyFactoryPolicy(factories) { const orderedFactories = factories.slice().reverse(); return { name: requestPolicyFactoryPolicyName, async sendRequest(request, next) { let httpPipeline = { async sendRequest(httpRequest) { const response = await next(toPipelineRequest(httpRequest)); return toCompatResponse(response, { createProxy: true }); }, }; for (const factory of orderedFactories) { httpPipeline = factory.create(httpPipeline, mockRequestPolicyOptions); } const webResourceLike = toWebResourceLike(request, { createProxy: true }); const response = await httpPipeline.sendRequest(webResourceLike); return toPipelineResponse(response); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Converts a RequestPolicy based HttpClient to a PipelineRequest based HttpClient. * @param requestPolicyClient - A HttpClient compatible with core-http * @returns A HttpClient compatible with core-rest-pipeline */ function convertHttpClient(requestPolicyClient) { return { sendRequest: async (request) => { const response = await requestPolicyClient.sendRequest(toWebResourceLike(request, { createProxy: true })); return toPipelineResponse(response); }, }; } const nameStartChar = ':A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD'; const nameChar = nameStartChar + '\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040'; const nameRegexp = '[' + nameStartChar + '][' + nameChar + ']*'; const regexName = new RegExp('^' + nameRegexp + '$'); function getAllMatches(string, regex) { const matches = []; let match = regex.exec(string); while (match) { const allmatches = []; allmatches.startIndex = regex.lastIndex - match[0].length; const len = match.length; for (let index = 0; index < len; index++) { allmatches.push(match[index]); } matches.push(allmatches); match = regex.exec(string); } return matches; } const isName = function (string) { const match = regexName.exec(string); return !(match === null || typeof match === 'undefined'); }; function isExist(v) { return typeof v !== 'undefined'; } /** * Dangerous property names that could lead to prototype pollution or security issues */ const DANGEROUS_PROPERTY_NAMES = [ // '__proto__', // 'constructor', // 'prototype', 'hasOwnProperty', 'toString', 'valueOf', '__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__' ]; const criticalProperties = ["__proto__", "constructor", "prototype"]; const defaultOptions$2 = { allowBooleanAttributes: false, //A tag can have attributes without any value unpairedTags: [] }; //const tagsPattern = new RegExp("<\\/?([\\w:\\-_\.]+)\\s*\/?>","g"); function validate(xmlData, options) { options = Object.assign({}, defaultOptions$2, options); //xmlData = xmlData.replace(/(\r\n|\n|\r)/gm,"");//make it single line //xmlData = xmlData.replace(/(^\s*<\?xml.*?\?>)/g,"");//Remove XML starting tag //xmlData = xmlData.replace(/()/g,"");//Remove DOCTYPE const tags = []; let tagFound = false; //indicates that the root tag has been closed (aka. depth 0 has been reached) let reachedRoot = false; if (xmlData[0] === '\ufeff') { // check for byte order mark (BOM) xmlData = xmlData.substr(1); } for (let i = 0; i < xmlData.length; i++) { if (xmlData[i] === '<' && xmlData[i + 1] === '?') { i += 2; i = readPI(xmlData, i); if (i.err) return i; } else if (xmlData[i] === '<') { //starting of tag //read until you reach to '>' avoiding any '>' in attribute value let tagStartPos = i; i++; if (xmlData[i] === '!') { i = readCommentAndCDATA(xmlData, i); continue; } else { let closingTag = false; if (xmlData[i] === '/') { //closing tag closingTag = true; i++; } //read tagname let tagName = ''; for (; i < xmlData.length && xmlData[i] !== '>' && xmlData[i] !== ' ' && xmlData[i] !== '\t' && xmlData[i] !== '\n' && xmlData[i] !== '\r'; i++ ) { tagName += xmlData[i]; } tagName = tagName.trim(); //console.log(tagName); if (tagName[tagName.length - 1] === '/') { //self closing tag without attributes tagName = tagName.substring(0, tagName.length - 1); //continue; i--; } if (!validateTagName(tagName)) { let msg; if (tagName.trim().length === 0) { msg = "Invalid space after '<'."; } else { msg = "Tag '" + tagName + "' is an invalid name."; } return getErrorObject('InvalidTag', msg, getLineNumberForPosition(xmlData, i)); } const result = readAttributeStr(xmlData, i); if (result === false) { return getErrorObject('InvalidAttr', "Attributes for '" + tagName + "' have open quote.", getLineNumberForPosition(xmlData, i)); } let attrStr = result.value; i = result.index; if (attrStr[attrStr.length - 1] === '/') { //self closing tag const attrStrStart = i - attrStr.length; attrStr = attrStr.substring(0, attrStr.length - 1); const isValid = validateAttributeString(attrStr, options); if (isValid === true) { tagFound = true; //continue; //text may presents after self closing tag } else { //the result from the nested function returns the position of the error within the attribute //in order to get the 'true' error line, we need to calculate the position where the attribute begins (i - attrStr.length) and then add the position within the attribute //this gives us the absolute index in the entire xml, which we can use to find the line at last return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, attrStrStart + isValid.err.line)); } } else if (closingTag) { if (!result.tagClosed) { return getErrorObject('InvalidTag', "Closing tag '" + tagName + "' doesn't have proper closing.", getLineNumberForPosition(xmlData, i)); } else if (attrStr.trim().length > 0) { return getErrorObject('InvalidTag', "Closing tag '" + tagName + "' can't have attributes or invalid starting.", getLineNumberForPosition(xmlData, tagStartPos)); } else if (tags.length === 0) { return getErrorObject('InvalidTag', "Closing tag '" + tagName + "' has not been opened.", getLineNumberForPosition(xmlData, tagStartPos)); } else { const otg = tags.pop(); if (tagName !== otg.tagName) { let openPos = getLineNumberForPosition(xmlData, otg.tagStartPos); return getErrorObject('InvalidTag', "Expected closing tag '" + otg.tagName + "' (opened in line " + openPos.line + ", col " + openPos.col + ") instead of closing tag '" + tagName + "'.", getLineNumberForPosition(xmlData, tagStartPos)); } //when there are no more tags, we reached the root level. if (tags.length == 0) { reachedRoot = true; } } } else { const isValid = validateAttributeString(attrStr, options); if (isValid !== true) { //the result from the nested function returns the position of the error within the attribute //in order to get the 'true' error line, we need to calculate the position where the attribute begins (i - attrStr.length) and then add the position within the attribute //this gives us the absolute index in the entire xml, which we can use to find the line at last return getErrorObject(isValid.err.code, isValid.err.msg, getLineNumberForPosition(xmlData, i - attrStr.length + isValid.err.line)); } //if the root level has been reached before ... if (reachedRoot === true) { return getErrorObject('InvalidXml', 'Multiple possible root nodes found.', getLineNumberForPosition(xmlData, i)); } else if (options.unpairedTags.indexOf(tagName) !== -1) ; else { tags.push({ tagName, tagStartPos }); } tagFound = true; } //skip tag text value //It may include comments and CDATA value for (i++; i < xmlData.length; i++) { if (xmlData[i] === '<') { if (xmlData[i + 1] === '!') { //comment or CADATA i++; i = readCommentAndCDATA(xmlData, i); continue; } else if (xmlData[i + 1] === '?') { i = readPI(xmlData, ++i); if (i.err) return i; } else { break; } } else if (xmlData[i] === '&') { const afterAmp = validateAmpersand(xmlData, i); if (afterAmp == -1) return getErrorObject('InvalidChar', "char '&' is not expected.", getLineNumberForPosition(xmlData, i)); i = afterAmp; } else { if (reachedRoot === true && !isWhiteSpace(xmlData[i])) { return getErrorObject('InvalidXml', "Extra text at the end", getLineNumberForPosition(xmlData, i)); } } } //end of reading tag text value if (xmlData[i] === '<') { i--; } } } else { if (isWhiteSpace(xmlData[i])) { continue; } return getErrorObject('InvalidChar', "char '" + xmlData[i] + "' is not expected.", getLineNumberForPosition(xmlData, i)); } } if (!tagFound) { return getErrorObject('InvalidXml', 'Start tag expected.', 1); } else if (tags.length == 1) { return getErrorObject('InvalidTag', "Unclosed tag '" + tags[0].tagName + "'.", getLineNumberForPosition(xmlData, tags[0].tagStartPos)); } else if (tags.length > 0) { return getErrorObject('InvalidXml', "Invalid '" + JSON.stringify(tags.map(t => t.tagName), null, 4).replace(/\r?\n/g, '') + "' found.", { line: 1, col: 1 }); } return true; } function isWhiteSpace(char) { return char === ' ' || char === '\t' || char === '\n' || char === '\r'; } /** * Read Processing insstructions and skip * @param {*} xmlData * @param {*} i */ function readPI(xmlData, i) { const start = i; for (; i < xmlData.length; i++) { if (xmlData[i] == '?' || xmlData[i] == ' ') { //tagname const tagname = xmlData.substr(start, i - start); if (i > 5 && tagname === 'xml') { return getErrorObject('InvalidXml', 'XML declaration allowed only at the start of the document.', getLineNumberForPosition(xmlData, i)); } else if (xmlData[i] == '?' && xmlData[i + 1] == '>') { //check if valid attribut string i++; break; } else { continue; } } } return i; } function readCommentAndCDATA(xmlData, i) { if (xmlData.length > i + 5 && xmlData[i + 1] === '-' && xmlData[i + 2] === '-') { //comment for (i += 3; i < xmlData.length; i++) { if (xmlData[i] === '-' && xmlData[i + 1] === '-' && xmlData[i + 2] === '>') { i += 2; break; } } } else if ( xmlData.length > i + 8 && xmlData[i + 1] === 'D' && xmlData[i + 2] === 'O' && xmlData[i + 3] === 'C' && xmlData[i + 4] === 'T' && xmlData[i + 5] === 'Y' && xmlData[i + 6] === 'P' && xmlData[i + 7] === 'E' ) { let angleBracketsCount = 1; for (i += 8; i < xmlData.length; i++) { if (xmlData[i] === '<') { angleBracketsCount++; } else if (xmlData[i] === '>') { angleBracketsCount--; if (angleBracketsCount === 0) { break; } } } } else if ( xmlData.length > i + 9 && xmlData[i + 1] === '[' && xmlData[i + 2] === 'C' && xmlData[i + 3] === 'D' && xmlData[i + 4] === 'A' && xmlData[i + 5] === 'T' && xmlData[i + 6] === 'A' && xmlData[i + 7] === '[' ) { for (i += 8; i < xmlData.length; i++) { if (xmlData[i] === ']' && xmlData[i + 1] === ']' && xmlData[i + 2] === '>') { i += 2; break; } } } return i; } const doubleQuote = '"'; const singleQuote = "'"; /** * Keep reading xmlData until '<' is found outside the attribute value. * @param {string} xmlData * @param {number} i */ function readAttributeStr(xmlData, i) { let attrStr = ''; let startChar = ''; let tagClosed = false; for (; i < xmlData.length; i++) { if (xmlData[i] === doubleQuote || xmlData[i] === singleQuote) { if (startChar === '') { startChar = xmlData[i]; } else if (startChar !== xmlData[i]) ; else { startChar = ''; } } else if (xmlData[i] === '>') { if (startChar === '') { tagClosed = true; break; } } attrStr += xmlData[i]; } if (startChar !== '') { return false; } return { value: attrStr, index: i, tagClosed: tagClosed }; } /** * Select all the attributes whether valid or invalid. */ const validAttrStrRegxp = new RegExp('(\\s*)([^\\s=]+)(\\s*=)?(\\s*([\'"])(([\\s\\S])*?)\\5)?', 'g'); //attr, ="sd", a="amit's", a="sd"b="saf", ab cd="" function validateAttributeString(attrStr, options) { //console.log("start:"+attrStr+":end"); //if(attrStr.trim().length === 0) return true; //empty string const matches = getAllMatches(attrStr, validAttrStrRegxp); const attrNames = {}; for (let i = 0; i < matches.length; i++) { if (matches[i][1].length === 0) { //nospace before attribute name: a="sd"b="saf" return getErrorObject('InvalidAttr', "Attribute '" + matches[i][2] + "' has no space in starting.", getPositionFromMatch(matches[i])) } else if (matches[i][3] !== undefined && matches[i][4] === undefined) { return getErrorObject('InvalidAttr', "Attribute '" + matches[i][2] + "' is without value.", getPositionFromMatch(matches[i])); } else if (matches[i][3] === undefined && !options.allowBooleanAttributes) { //independent attribute: ab return getErrorObject('InvalidAttr', "boolean attribute '" + matches[i][2] + "' is not allowed.", getPositionFromMatch(matches[i])); } /* else if(matches[i][6] === undefined){//attribute without value: ab= return { err: { code:"InvalidAttr",msg:"attribute " + matches[i][2] + " has no value assigned."}}; } */ const attrName = matches[i][2]; if (!validateAttrName(attrName)) { return getErrorObject('InvalidAttr', "Attribute '" + attrName + "' is an invalid name.", getPositionFromMatch(matches[i])); } if (!Object.prototype.hasOwnProperty.call(attrNames, attrName)) { //check for duplicate attribute. attrNames[attrName] = 1; } else { return getErrorObject('InvalidAttr', "Attribute '" + attrName + "' is repeated.", getPositionFromMatch(matches[i])); } } return true; } function validateNumberAmpersand(xmlData, i) { let re = /\d/; if (xmlData[i] === 'x') { i++; re = /[\da-fA-F]/; } for (; i < xmlData.length; i++) { if (xmlData[i] === ';') return i; if (!xmlData[i].match(re)) break; } return -1; } function validateAmpersand(xmlData, i) { // https://www.w3.org/TR/xml/#dt-charref i++; if (xmlData[i] === ';') return -1; if (xmlData[i] === '#') { i++; return validateNumberAmpersand(xmlData, i); } let count = 0; for (; i < xmlData.length; i++, count++) { if (xmlData[i].match(/\w/) && count < 20) continue; if (xmlData[i] === ';') break; return -1; } return i; } function getErrorObject(code, message, lineNumber) { return { err: { code: code, msg: message, line: lineNumber.line || lineNumber, col: lineNumber.col, }, }; } function validateAttrName(attrName) { return isName(attrName); } // const startsWithXML = /^xml/i; function validateTagName(tagname) { return isName(tagname) /* && !tagname.match(startsWithXML) */; } //this function returns the line number for the character at the given index function getLineNumberForPosition(xmlData, index) { const lines = xmlData.substring(0, index).split(/\r?\n/); return { line: lines.length, // column number is last line's length + 1, because column numbering starts at 1: col: lines[lines.length - 1].length + 1 }; } //this function returns the position of the first character of match within attrStr function getPositionFromMatch(match) { return match.startIndex + match[1].length; } // --------------------------------------------------------------------------- // Complete HTML5 named entity reference // Organized by logical categories for easy maintenance and selective importing // --------------------------------------------------------------------------- /** * Currency Symbols * @type {Record} */ const CURRENCY = { cent: '¢', pound: '£', curren: '¤', yen: '¥', euro: '€', dollar: '$', fnof: 'ƒ', inr: '₹', af: '؋', birr: 'ብር', peso: '₱', rub: '₽', won: '₩', yuan: '¥', cedil: '¸', }; const XML = { amp: "&", apos: "'", gt: ">", lt: "<", quot: "\"" }; const COMMON_HTML = { nbsp: '\u00a0', copy: '\u00a9', reg: '\u00ae', trade: '\u2122', mdash: '\u2014', ndash: '\u2013', hellip: '\u2026', laquo: '\u00ab', raquo: '\u00bb', lsquo: '\u2018', rsquo: '\u2019', ldquo: '\u201c', rdquo: '\u201d', bull: '\u2022', para: '\u00b6', sect: '\u00a7', deg: '\u00b0', frac12: '\u00bd', frac14: '\u00bc', frac34: '\u00be', }; // --------------------------------------------------------------------------- // Note: NUMERIC_ENTITIES (&#NNN; / &#xHH;) are handled by the scanner directly // via String.fromCodePoint() without any map lookup. // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // Built-in named entity map (name → replacement string) // No regex, no {regex,val} objects — just flat key/value pairs. // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- const SPECIAL_CHARS = new Set('!?\\\\/[]$%{}^&*()<>|+'); /** * Validate that an entity name contains no dangerous characters. * @param {string} name * @returns {string} the name, unchanged * @throws {Error} on invalid characters */ function validateEntityName$1(name) { if (name[0] === '#') { throw new Error(`[EntityReplacer] Invalid character '#' in entity name: "${name}"`); } for (const ch of name) { if (SPECIAL_CHARS.has(ch)) { throw new Error(`[EntityReplacer] Invalid character '${ch}' in entity name: "${name}"`); } } return name; } /** * Merge one or more entity maps into a flat name→string map. * Accepts either: * - plain string values: { amp: '&' } * - legacy {regex,val} / {regx,val}: { lt: { regex: /.../, val: '<' } } * * Values containing '&' are skipped (recursive expansion risk). * * @param {...object} maps * @returns {Record} */ function mergeEntityMaps(...maps) { const out = Object.create(null); for (const map of maps) { if (!map) continue; for (const key of Object.keys(map)) { const raw = map[key]; if (typeof raw === 'string') { out[key] = raw; } else if (raw && typeof raw === 'object' && raw.val !== undefined) { // Legacy {regex,val} or {regx,val} — extract the string val only const val = raw.val; if (typeof val === 'string') { out[key] = val; } // function vals are not supported in the scanner — skip } } } return out; } // --------------------------------------------------------------------------- // applyLimitsTo helpers // --------------------------------------------------------------------------- const LIMIT_TIER_EXTERNAL = 'external'; // input/runtime + persistent external maps const LIMIT_TIER_BASE = 'base'; // DEFAULT_XML_ENTITIES + namedEntities (system) maps const LIMIT_TIER_ALL = 'all'; // every entity regardless of tier /** * Resolve `applyLimitsTo` option into a normalised Set of tier strings. * Accepted values: 'external' | 'base' | 'all' | string[] * Default: 'external' (only untrusted injected entities are counted). * @param {string|string[]|undefined} raw * @returns {Set} */ function parseLimitTiers(raw) { if (!raw || raw === LIMIT_TIER_EXTERNAL) return new Set([LIMIT_TIER_EXTERNAL]); if (raw === LIMIT_TIER_ALL) return new Set([LIMIT_TIER_ALL]); if (raw === LIMIT_TIER_BASE) return new Set([LIMIT_TIER_BASE]); if (Array.isArray(raw)) return new Set(raw); return new Set([LIMIT_TIER_EXTERNAL]); // safe default for unrecognised values } // --------------------------------------------------------------------------- // NCR (Numeric Character Reference) classification // --------------------------------------------------------------------------- // Severity order — higher number = stricter action. // Used to enforce minimum action levels for specific codepoint ranges. const NCR_LEVEL = Object.freeze({ allow: 0, leave: 1, remove: 2, throw: 3 }); // XML 1.0 §2.2: allowed chars are #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] // Restricted C0: U+0001–U+001F excluding U+0009, U+000A, U+000D const XML10_ALLOWED_C0 = new Set([0x09, 0x0A, 0x0D]); /** * Parse the `ncr` constructor option into flat, hot-path-friendly fields. * @param {object|undefined} ncr * @returns {{ xmlVersion: number, onLevel: number, nullLevel: number }} */ function parseNCRConfig(ncr) { if (!ncr) { return { xmlVersion: 1.0, onLevel: NCR_LEVEL.allow, nullLevel: NCR_LEVEL.remove }; } const xmlVersion = ncr.xmlVersion === 1.1 ? 1.1 : 1.0; const onLevel = NCR_LEVEL[ncr.onNCR] ?? NCR_LEVEL.allow; const nullLevel = NCR_LEVEL[ncr.nullNCR] ?? NCR_LEVEL.remove; // 'allow' is not meaningful for null — clamp to at least 'remove' const clampedNull = Math.max(nullLevel, NCR_LEVEL.remove); return { xmlVersion, onLevel, nullLevel: clampedNull }; } // --------------------------------------------------------------------------- // EntityReplacer // --------------------------------------------------------------------------- /** * Single-pass, zero-regex entity replacer for XML/HTML content. * * Algorithm: scan the string once for '&', read to ';', resolve via map * or direct codepoint conversion, build output chunks, join once at the end. * * Entity lookup priority (highest → lowest): * 1. input / runtime (DOCTYPE entities for current document) * 2. persistent external (survive across documents) * 3. base named map (DEFAULT_XML_ENTITIES + user-supplied namedEntities) * * Both input and external resolve as the 'external' tier for limit purposes. * Base map entities resolve as the 'base' tier. * * Numeric / hex references (&#NNN; / &#xHH;) are resolved directly via * String.fromCodePoint() — no map needed. They count as 'base' tier. * * @example * const replacer = new EntityReplacer({ namedEntities: COMMON_HTML }); * replacer.setExternalEntities({ brand: 'Acme' }); * * const instance = replacer.reset(); * instance.addInputEntities({ version: '1.0' }); * instance.encode('&brand; v&version; <'); // 'Acme v1.0 <' */ class EntityDecoder { /** * @param {object} [options] * @param {object|null} [options.namedEntities] — extra named entities merged into base map * @param {object} [options.limit] — security limits * @param {number} [options.limit.maxTotalExpansions=0] — 0 = unlimited * @param {number} [options.limit.maxExpandedLength=0] — 0 = unlimited * @param {'external'|'base'|'all'|string[]} [options.limit.applyLimitsTo='external'] * Which entity tiers count against the security limits: * - 'external' (default) — only input/runtime + persistent external entities * - 'base' — only DEFAULT_XML_ENTITIES + namedEntities * - 'all' — every entity regardless of tier * - string[] — explicit combination, e.g. ['external', 'base'] * @param {((resolved: string, original: string) => string)|null} [options.postCheck=null] * @param {string[]} [options.remove=[]] — entity names (e.g. ['nbsp', '#13']) to delete (replace with empty string) * @param {string[]} [options.leave=[]] — entity names to keep as literal (unchanged in output) * @param {object} [options.ncr] — Numeric Character Reference controls * @param {1.0|1.1} [options.ncr.xmlVersion=1.0] * XML version governing which codepoint ranges are restricted: * - 1.0 — C0 controls U+0001–U+001F (except U+0009/000A/000D) are prohibited * - 1.1 — C0 controls are allowed when written as NCRs; C1 (U+007F–U+009F) decoded as-is * @param {'allow'|'leave'|'remove'|'throw'} [options.ncr.onNCR='allow'] * Base action for numeric references. Severity order: allow < leave < remove < throw. * For codepoint ranges that carry a minimum level (surrogates → remove, XML 1.0 C0 → remove), * the effective action is max(onNCR, rangeMinimum). * @param {'remove'|'throw'} [options.ncr.nullNCR='remove'] * Action for U+0000 (null). 'allow' and 'leave' are clamped to 'remove' since null is never safe. */ constructor(options = {}) { this._limit = options.limit || {}; this._maxTotalExpansions = this._limit.maxTotalExpansions || 0; this._maxExpandedLength = this._limit.maxExpandedLength || 0; this._postCheck = typeof options.postCheck === 'function' ? options.postCheck : r => r; this._limitTiers = parseLimitTiers(this._limit.applyLimitsTo ?? LIMIT_TIER_EXTERNAL); this._numericAllowed = options.numericAllowed ?? true; // Base map: DEFAULT_XML_ENTITIES + user-supplied extras. Immutable after construction. this._baseMap = mergeEntityMaps(XML, options.namedEntities || null); // Persistent external entities — survive across documents. // Stored as a separate map so reset() never touches them. /** @type {Record} */ this._externalMap = Object.create(null); // Input / runtime entities — current document only, wiped on reset(). /** @type {Record} */ this._inputMap = Object.create(null); // Per-document counters this._totalExpansions = 0; this._expandedLength = 0; // --- New: remove / leave sets --- /** @type {Set} */ this._removeSet = new Set(options.remove && Array.isArray(options.remove) ? options.remove : []); /** @type {Set} */ this._leaveSet = new Set(options.leave && Array.isArray(options.leave) ? options.leave : []); // --- NCR config (parsed into flat fields for hot-path speed) --- const ncrCfg = parseNCRConfig(options.ncr); this._ncrXmlVersion = ncrCfg.xmlVersion; this._ncrOnLevel = ncrCfg.onLevel; this._ncrNullLevel = ncrCfg.nullLevel; } // ------------------------------------------------------------------------- // Persistent external entity registration // ------------------------------------------------------------------------- /** * Replace the full set of persistent external entities. * All keys are validated — throws on invalid characters. * @param {Record} map */ setExternalEntities(map) { if (map) { for (const key of Object.keys(map)) { validateEntityName$1(key); } } this._externalMap = mergeEntityMaps(map); } /** * Add a single persistent external entity. * @param {string} key * @param {string} value */ addExternalEntity(key, value) { validateEntityName$1(key); if (typeof value === 'string' && value.indexOf('&') === -1) { this._externalMap[key] = value; } } // ------------------------------------------------------------------------- // Input / runtime entity registration (per document) // ------------------------------------------------------------------------- /** * Inject DOCTYPE entities for the current document. * Also resets per-document expansion counters. * @param {Record} map */ addInputEntities(map) { this._totalExpansions = 0; this._expandedLength = 0; this._inputMap = mergeEntityMaps(map); } // ------------------------------------------------------------------------- // Per-document reset // ------------------------------------------------------------------------- /** * Wipe input/runtime entities and reset counters. * Call this before processing each new document. * @returns {this} */ reset() { this._inputMap = Object.create(null); this._totalExpansions = 0; this._expandedLength = 0; return this; } // ------------------------------------------------------------------------- // XML version (can be set after construction, e.g. once parser reads ) // ------------------------------------------------------------------------- /** * Update the XML version used for NCR classification. * Call this as soon as the document's `` declaration is parsed. * @param {1.0|1.1|number} version */ setXmlVersion(version) { this._ncrXmlVersion = version === 1.1 ? 1.1 : 1.0; } // ------------------------------------------------------------------------- // Primary API // ------------------------------------------------------------------------- /** * Replace all entity references in `str` in a single pass. * * @param {string} str * @returns {string} */ decode(str) { if (typeof str !== 'string' || str.length === 0) return str; //TODO: check if needed if (str.indexOf('&') === -1) return str; // fast path — no entities at all const original = str; const chunks = []; const len = str.length; let last = 0; // start of next unprocessed literal chunk let i = 0; const limitExpansions = this._maxTotalExpansions > 0; const limitLength = this._maxExpandedLength > 0; const checkLimits = limitExpansions || limitLength; while (i < len) { // Scan forward to next '&' if (str.charCodeAt(i) !== 38 /* '&' */) { i++; continue; } // --- Found '&' at position i --- // Scan forward to ';' let j = i + 1; while (j < len && str.charCodeAt(j) !== 59 /* ';' */ && (j - i) <= 32) j++; if (j >= len || str.charCodeAt(j) !== 59) { // No closing ';' within window — treat '&' as literal i++; continue; } // Raw token between '&' and ';' (exclusive) const token = str.slice(i + 1, j); if (token.length === 0) { i++; continue; } let replacement; let tier; // which limit tier this entity belongs to if (this._removeSet.has(token)) { // Remove entity: replace with empty string replacement = ''; // If entity was unknown (replacement undefined), we still need a tier for limits. // Treat as external tier because it's user-directed removal of an unknown reference. if (tier === undefined) { tier = LIMIT_TIER_EXTERNAL; } } else if (this._leaveSet.has(token)) { // Do not replace — keep original &token; as literal i++; continue; } else if (token.charCodeAt(0) === 35 /* '#' */) { // ---- Numeric / NCR reference ---- // NCR classification always runs first — prohibited codepoints must be // caught regardless of numericAllowed. const ncrResult = this._resolveNCR(token); if (ncrResult === undefined) { // 'leave' action — keep original &token; as-is i++; continue; } replacement = ncrResult; // '' for remove, char string for allow tier = LIMIT_TIER_BASE; } else { // ---- Named reference ---- const resolved = this._resolveName(token); replacement = resolved?.value; tier = resolved?.tier; } if (replacement === undefined) { // Unknown entity — leave as-is, advance past '&' only i++; continue; } // Flush literal chunk before this entity if (i > last) chunks.push(str.slice(last, i)); chunks.push(replacement); last = j + 1; // skip past ';' i = last; // Apply expansion limits only if this tier is being tracked if (checkLimits && this._tierCounts(tier)) { if (limitExpansions) { this._totalExpansions++; if (this._totalExpansions > this._maxTotalExpansions) { throw new Error( `[EntityReplacer] Entity expansion count limit exceeded: ` + `${this._totalExpansions} > ${this._maxTotalExpansions}` ); } } if (limitLength) { // delta: replacement.length minus the raw &token; length (token.length + 2 for '&' and ';') const delta = replacement.length - (token.length + 2); if (delta > 0) { this._expandedLength += delta; if (this._expandedLength > this._maxExpandedLength) { throw new Error( `[EntityReplacer] Expanded content length limit exceeded: ` + `${this._expandedLength} > ${this._maxExpandedLength}` ); } } } } } // Flush trailing literal if (last < len) chunks.push(str.slice(last)); // If nothing was replaced, chunks is empty — return original const result = chunks.length === 0 ? str : chunks.join(''); return this._postCheck(result, original); } // ------------------------------------------------------------------------- // Private: limit tier check // ------------------------------------------------------------------------- /** * Returns true if a resolved entity of the given tier should count * against the expansion/length limits. * @param {string} tier — LIMIT_TIER_EXTERNAL | LIMIT_TIER_BASE * @returns {boolean} */ _tierCounts(tier) { if (this._limitTiers.has(LIMIT_TIER_ALL)) return true; return this._limitTiers.has(tier); } // ------------------------------------------------------------------------- // Private: entity resolution // ------------------------------------------------------------------------- /** * Resolve a named entity token (without & and ;). * Priority: inputMap > externalMap > baseMap * Returns the resolved value tagged with its limit tier. * * @param {string} name * @returns {{ value: string, tier: string }|undefined} */ _resolveName(name) { // input and external both count as 'external' tier for limit purposes — // they are injected at runtime and are the untrusted surface. if (name in this._inputMap) return { value: this._inputMap[name], tier: LIMIT_TIER_EXTERNAL }; if (name in this._externalMap) return { value: this._externalMap[name], tier: LIMIT_TIER_EXTERNAL }; if (name in this._baseMap) return { value: this._baseMap[name], tier: LIMIT_TIER_BASE }; return undefined; } /** * Classify a codepoint and return the minimum action level that must be applied. * Returns -1 when no minimum is imposed (normal allow path). * * Ranges checked (in priority order): * 1. U+0000 — null, governed by nullNCR (always ≥ remove) * 2. U+D800–U+DFFF — surrogates, always prohibited (min: remove) * 3. U+0001–U+001F \ {0x09,0x0A,0x0D} — XML 1.0 restricted C0 (min: remove) * (skipped in XML 1.1 — C0 controls are allowed when written as NCRs) * * @param {number} cp — codepoint * @returns {number} — minimum NCR_LEVEL value, or -1 for no restriction */ _classifyNCR(cp) { // 1. Null if (cp === 0) return this._ncrNullLevel; // 2. Surrogates — always prohibited, minimum 'remove' if (cp >= 0xD800 && cp <= 0xDFFF) return NCR_LEVEL.remove; // 3. XML 1.0 restricted C0 controls if (this._ncrXmlVersion === 1.0) { if (cp >= 0x01 && cp <= 0x1F && !XML10_ALLOWED_C0.has(cp)) return NCR_LEVEL.remove; } return -1; // no restriction } /** * Execute a resolved NCR action. * * @param {number} action — NCR_LEVEL value * @param {string} token — raw token (e.g. '#38') for error messages * @param {number} cp — codepoint, used only for error messages * @returns {string|undefined} * - decoded character string → 'allow' * - '' → 'remove' * - undefined → 'leave' (caller must skip past '&' only) * - throws Error → 'throw' */ _applyNCRAction(action, token, cp) { switch (action) { case NCR_LEVEL.allow: return String.fromCodePoint(cp); case NCR_LEVEL.remove: return ''; case NCR_LEVEL.leave: return undefined; // signal: keep literal case NCR_LEVEL.throw: throw new Error( `[EntityDecoder] Prohibited numeric character reference ` + `&${token}; (U+${cp.toString(16).toUpperCase().padStart(4, '0')})` ); default: return String.fromCodePoint(cp); } } /** * Full NCR resolution pipeline for a numeric token. * * Steps: * 1. Parse the codepoint (decimal or hex). * 2. Validate the raw codepoint range (NaN, <0, >0x10FFFF). * 3. If numericAllowed is false and no minimum restriction applies → leave as-is. * 4. Classify the codepoint to find the minimum required action level. * 5. Resolve effective action = max(onNCR, minimum). * 6. Apply and return. * * @param {string} token — e.g. '#38', '#x26', '#X26' * @returns {string|undefined} * - string (incl. '') — replacement ('' = remove) * - undefined — leave original &token; as-is */ _resolveNCR(token) { // Step 1: parse codepoint const second = token.charCodeAt(1); let cp; if (second === 120 /* x */ || second === 88 /* X */) { cp = parseInt(token.slice(2), 16); } else { cp = parseInt(token.slice(1), 10); } // Step 2: out-of-range → leave as-is unconditionally if (Number.isNaN(cp) || cp < 0 || cp > 0x10FFFF) return undefined; // Step 3: classify to get minimum action level const minimum = this._classifyNCR(cp); // Step 4: if numericAllowed is false and no hard minimum → leave if (!this._numericAllowed && minimum < NCR_LEVEL.remove) return undefined; // Step 5: effective action = max(configured onNCR, range minimum) const effective = minimum === -1 ? this._ncrOnLevel : Math.max(this._ncrOnLevel, minimum); // Step 6: apply return this._applyNCRAction(effective, token, cp); } } const defaultOnDangerousProperty = (name) => { if (DANGEROUS_PROPERTY_NAMES.includes(name)) { return "__" + name; } return name; }; const defaultOptions$1 = { preserveOrder: false, attributeNamePrefix: '@_', attributesGroupName: false, textNodeName: '#text', ignoreAttributes: true, removeNSPrefix: false, // remove NS from tag name or attribute name if true allowBooleanAttributes: false, //a tag can have attributes without any value //ignoreRootElement : false, parseTagValue: true, parseAttributeValue: false, trimValues: true, //Trim string values of tag and attributes cdataPropName: false, numberParseOptions: { hex: true, leadingZeros: true, eNotation: true }, tagValueProcessor: function (tagName, val) { return val; }, attributeValueProcessor: function (attrName, val) { return val; }, stopNodes: [], //nested tags will not be parsed even for errors alwaysCreateTextNode: false, isArray: () => false, commentPropName: false, unpairedTags: [], processEntities: true, htmlEntities: false, entityDecoder: null, ignoreDeclaration: false, ignorePiTags: false, transformTagName: false, transformAttributeName: false, updateTag: function (tagName, jPath, attrs) { return tagName }, // skipEmptyListItem: false captureMetaData: false, maxNestedTags: 100, strictReservedNames: true, jPath: true, // if true, pass jPath string to callbacks; if false, pass matcher instance onDangerousProperty: defaultOnDangerousProperty }; /** * Validates that a property name is safe to use * @param {string} propertyName - The property name to validate * @param {string} optionName - The option field name (for error message) * @throws {Error} If property name is dangerous */ function validatePropertyName(propertyName, optionName) { if (typeof propertyName !== 'string') { return; // Only validate string property names } const normalized = propertyName.toLowerCase(); if (DANGEROUS_PROPERTY_NAMES.some(dangerous => normalized === dangerous.toLowerCase())) { throw new Error( `[SECURITY] Invalid ${optionName}: "${propertyName}" is a reserved JavaScript keyword that could cause prototype pollution` ); } if (criticalProperties.some(dangerous => normalized === dangerous.toLowerCase())) { throw new Error( `[SECURITY] Invalid ${optionName}: "${propertyName}" is a reserved JavaScript keyword that could cause prototype pollution` ); } } /** * Normalizes processEntities option for backward compatibility * @param {boolean|object} value * @returns {object} Always returns normalized object */ function normalizeProcessEntities(value, htmlEntities) { // Boolean backward compatibility if (typeof value === 'boolean') { return { enabled: value, // true or false maxEntitySize: 10000, maxExpansionDepth: 10000, maxTotalExpansions: Infinity, maxExpandedLength: 100000, maxEntityCount: 1000, allowedTags: null, tagFilter: null, appliesTo: "all", }; } // Object config - merge with defaults if (typeof value === 'object' && value !== null) { return { enabled: value.enabled !== false, maxEntitySize: Math.max(1, value.maxEntitySize ?? 10000), maxExpansionDepth: Math.max(1, value.maxExpansionDepth ?? 10000), maxTotalExpansions: Math.max(1, value.maxTotalExpansions ?? Infinity), maxExpandedLength: Math.max(1, value.maxExpandedLength ?? 100000), maxEntityCount: Math.max(1, value.maxEntityCount ?? 1000), allowedTags: value.allowedTags ?? null, tagFilter: value.tagFilter ?? null, appliesTo: value.appliesTo ?? "all", }; } // Default to enabled with limits return normalizeProcessEntities(true); } const buildOptions = function (options) { const built = Object.assign({}, defaultOptions$1, options); // Validate property names to prevent prototype pollution const propertyNameOptions = [ { value: built.attributeNamePrefix, name: 'attributeNamePrefix' }, { value: built.attributesGroupName, name: 'attributesGroupName' }, { value: built.textNodeName, name: 'textNodeName' }, { value: built.cdataPropName, name: 'cdataPropName' }, { value: built.commentPropName, name: 'commentPropName' } ]; for (const { value, name } of propertyNameOptions) { if (value) { validatePropertyName(value, name); } } if (built.onDangerousProperty === null) { built.onDangerousProperty = defaultOnDangerousProperty; } // Always normalize processEntities for backward compatibility and validation built.processEntities = normalizeProcessEntities(built.processEntities, built.htmlEntities); built.unpairedTagsSet = new Set(built.unpairedTags); // Convert old-style stopNodes for backward compatibility if (built.stopNodes && Array.isArray(built.stopNodes)) { built.stopNodes = built.stopNodes.map(node => { if (typeof node === 'string' && node.startsWith('*.')) { // Old syntax: *.tagname meant "tagname anywhere" // Convert to new syntax: ..tagname return '..' + node.substring(2); } return node; }); } //console.debug(built.processEntities) return built; }; let METADATA_SYMBOL$1; if (typeof Symbol !== "function") { METADATA_SYMBOL$1 = "@@xmlMetadata"; } else { METADATA_SYMBOL$1 = Symbol("XML Node Metadata"); } class XmlNode { constructor(tagname) { this.tagname = tagname; this.child = []; //nested tags, text, cdata, comments in order this[":@"] = Object.create(null); //attributes map } add(key, val) { // this.child.push( {name : key, val: val, isCdata: isCdata }); if (key === "__proto__") key = "#__proto__"; this.child.push({ [key]: val }); } addChild(node, startIndex) { if (node.tagname === "__proto__") node.tagname = "#__proto__"; if (node[":@"] && Object.keys(node[":@"]).length > 0) { this.child.push({ [node.tagname]: node.child, [":@"]: node[":@"] }); } else { this.child.push({ [node.tagname]: node.child }); } // if requested, add the startIndex if (startIndex !== undefined) { // Note: for now we just overwrite the metadata. If we had more complex metadata, // we might need to do an object append here: metadata = { ...metadata, startIndex } this.child[this.child.length - 1][METADATA_SYMBOL$1] = { startIndex }; } } /** symbol used for metadata */ static getMetaDataSymbol() { return METADATA_SYMBOL$1; } } /** * xml-naming * Validates XML Name productions as defined in the XML 1.0 and 1.1 specifications. * Covers: Name, NCName, QName, NMToken, NMTokens * * XML 1.0 spec: https://www.w3.org/TR/xml/#NT-Name * XML 1.1 spec: https://www.w3.org/TR/xml11/#NT-NameStartChar * XML NS spec: https://www.w3.org/TR/xml-names/#NT-NCName */ // --------------------------------------------------------------------------- // Character class strings — XML 1.0 // // NameStartChar ::= ":" | [A-Z] | "_" | [a-z] // | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] // | [#x370-#x37D] | [#x37F-#x1FFF] <- split to exclude #x0487 // | [#x200C-#x200D] // | [#x2070-#x218F] | [#x2C00-#x2FEF] // | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] // // NameChar ::= NameStartChar | "-" | "." | [0-9] // | #xB7 | [#x0300-#x036F] | [#x203F-#x2040] // // Note: \u0487 (Combining Cyrillic Millions Sign) was added in Unicode 4.0, // after XML 1.0 was defined against Unicode 2.0. It falls inside the range // \u037F-\u1FFF but must be excluded. We split that range into // \u037F-\u0486 and \u0488-\u1FFF to exclude it explicitly. // --------------------------------------------------------------------------- const nameStartChar10 = ':A-Za-z_' + '\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF' + '\u0370-\u037D' + '\u037F-\u0486\u0488-\u1FFF' + // split to exclude \u0487 '\u200C-\u200D' + '\u2070-\u218F' + '\u2C00-\u2FEF' + '\u3001-\uD7FF' + '\uF900-\uFDCF' + '\uFDF0-\uFFFD'; const nameChar10 = nameStartChar10 + '\\-\\.\\d' + '\u00B7' + '\u0300-\u036F' + '\u203F-\u2040'; // --------------------------------------------------------------------------- // Character class strings — XML 1.1 // // Differences from XML 1.0: // // NameStartChar: // 1.0 has split ranges: \u00C0-\u00D6, \u00D8-\u00F6, \u00F8-\u02FF // 1.1 merges them into: \u00C0-\u02FF // (\u00D7 x and \u00F7 / are division symbols, excluded in both versions) // // 1.0 tops out at \uFFFD (BMP only) // 1.1 adds \u{10000}-\u{EFFFF} (supplementary planes) // These require the /u flag on the RegExp — see buildRegexes below. // // NameChar: // 1.1 adds \u0487 (Combining Cyrillic Millions Sign, added in Unicode 4.0) // --------------------------------------------------------------------------- const nameStartChar11 = ':A-Za-z_' + '\u00C0-\u02FF' + // merged — 1.0 had three split ranges here '\u0370-\u037D' + '\u037F-\u0486\u0488-\u1FFF' + // split to exclude \u0487 (combining mark, never a NameStartChar) '\u200C-\u200D' + '\u2070-\u218F' + '\u2C00-\u2FEF' + '\u3001-\uD7FF' + '\uF900-\uFDCF' + '\uFDF0-\uFFFD' + '\u{10000}-\u{EFFFF}'; // supplementary planes — REQUIRES /u flag on RegExp const nameChar11 = nameStartChar11 + '\\-\\.\\d' + '\u00B7' + '\u0300-\u036F' + '\u0487' + // Combining Cyrillic Millions Sign — valid in 1.1, not 1.0 '\u203F-\u2040'; // --------------------------------------------------------------------------- // Regex builders // // XML 1.0 regexes: no flags — BMP only, standard JS regex behaviour. // XML 1.1 regexes: /u flag — required for \u{10000}-\u{EFFFF} to match actual // supplementary code points rather than lone surrogates (which are illegal XML). // --------------------------------------------------------------------------- const buildRegexes = (startChar, char, flags = '') => { const ncStart = startChar.replace(':', ''); const ncChar = char.replace(':', ''); const ncNamePat = `[${ncStart}][${ncChar}]*`; return { name: new RegExp(`^[${startChar}][${char}]*$`, flags), ncName: new RegExp(`^${ncNamePat}$`, flags), qName: new RegExp(`^${ncNamePat}(?::${ncNamePat})?$`, flags), nmToken: new RegExp(`^[${char}]+$`, flags), nmTokens: new RegExp(`^[${char}]+(?:\\s+[${char}]+)*$`, flags), }; }; const regexes10 = buildRegexes(nameStartChar10, nameChar10); // no /u — BMP only const regexes11 = buildRegexes(nameStartChar11, nameChar11, 'u'); // /u — enables \u{10000}-\u{EFFFF} const getRegexes = (xmlVersion = '1.0') => xmlVersion === '1.1' ? regexes11 : regexes10; /** * Returns true if the string is a valid QName (Qualified Name). * Allows exactly one colon as a prefix separator: prefix:localName. * Used for: element and attribute names in namespace-aware XML/SVG. */ const qName = (str, { xmlVersion = '1.0' } = {}) => getRegexes(xmlVersion).qName.test(str); class DocTypeReader { constructor(options, xmlVersion) { this.suppressValidationErr = !options; this.options = options; this.xmlVersion = xmlVersion || 1.0; } setXmlVersion(xmlVersion = 1.0) { this.xmlVersion = xmlVersion; } readDocType(xmlData, i) { const entities = Object.create(null); let entityCount = 0; if (xmlData[i + 3] === 'O' && xmlData[i + 4] === 'C' && xmlData[i + 5] === 'T' && xmlData[i + 6] === 'Y' && xmlData[i + 7] === 'P' && xmlData[i + 8] === 'E') { i = i + 9; let angleBracketsCount = 1; let hasBody = false, comment = false; let exp = ""; for (; i < xmlData.length; i++) { if (xmlData[i] === '<' && !comment) { //Determine the tag type if (hasBody && hasSeq(xmlData, "!ENTITY", i)) { i += 7; let entityName, val; [entityName, val, i] = this.readEntityExp(xmlData, i + 1, this.suppressValidationErr); if (val.indexOf("&") === -1) { //Parameter entities are not supported if (this.options.enabled !== false && this.options.maxEntityCount != null && entityCount >= this.options.maxEntityCount) { throw new Error( `Entity count (${entityCount + 1}) exceeds maximum allowed (${this.options.maxEntityCount})` ); } //const escaped = entityName.replace(/[.\-+*:]/g, '\\.'); //const escaped = entityName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); entities[entityName] = val; entityCount++; } } else if (hasBody && hasSeq(xmlData, "!ELEMENT", i)) { i += 8;//Not supported const { index } = this.readElementExp(xmlData, i + 1); i = index; } else if (hasBody && hasSeq(xmlData, "!ATTLIST", i)) { i += 8;//Not supported // const {index} = this.readAttlistExp(xmlData,i+1); // i = index; } else if (hasBody && hasSeq(xmlData, "!NOTATION", i)) { i += 9;//Not supported const { index } = this.readNotationExp(xmlData, i + 1, this.suppressValidationErr); i = index; } else if (hasSeq(xmlData, "!--", i)) comment = true; else throw new Error(`Invalid DOCTYPE`); angleBracketsCount++; exp = ""; } else if (xmlData[i] === '>') { //Read tag content if (comment) { if (xmlData[i - 1] === "-" && xmlData[i - 2] === "-") { comment = false; angleBracketsCount--; } } else { angleBracketsCount--; } if (angleBracketsCount === 0) { break; } } else if (xmlData[i] === '[') { hasBody = true; } else { exp += xmlData[i]; } } if (angleBracketsCount !== 0) { throw new Error(`Unclosed DOCTYPE`); } } else { throw new Error(`Invalid Tag instead of DOCTYPE`); } return { entities, i }; } readEntityExp(xmlData, i) { //External entities are not supported // //Parameter entities are not supported // //Internal entities are supported // // Skip leading whitespace after this.options.maxEntitySize) { throw new Error( `Entity "${entityName}" size (${entityValue.length}) exceeds maximum allowed size (${this.options.maxEntitySize})` ); } i--; return [entityName, entityValue, i]; } readNotationExp(xmlData, i) { // Skip leading whitespace after // // // // // Skip leading whitespace after { while (index < data.length && /\s/.test(data[index])) { index++; } return index; }; function hasSeq(data, seq, i) { for (let j = 0; j < seq.length; j++) { if (seq[j] !== data[i + j + 1]) return false; } return true; } function validateEntityName(name, xmlVersion) { if (qName(name, { xmlVersion: xmlVersion })) return name; else throw new Error(`Invalid entity name ${name}`); } const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/; const binRegex = /^0b[01]+$/; const octRegex = /^0o[0-7]+$/; const numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/; const consider = { hex: true, binary: false, octal: false, leadingZeros: true, decimalPoint: "\.", eNotation: true, //skipLike: /regex/, infinity: "original", // "null", "infinity" (Infinity type), "string" ("Infinity" (the string literal)) }; function toNumber(str, options = {}) { options = Object.assign({}, consider, options); if (!str || typeof str !== "string") return str; let trimmedStr = str.trim(); if (trimmedStr.length === 0) return str; else if (options.skipLike !== undefined && options.skipLike.test(trimmedStr)) return str; else if (trimmedStr === "0") return 0; else if (options.hex && hexRegex.test(trimmedStr)) { return parse_int(trimmedStr, 16); } else if (options.binary && binRegex.test(trimmedStr)) { return parse_int(trimmedStr, 2); } else if (options.octal && octRegex.test(trimmedStr)) { return parse_int(trimmedStr, 8); } else if (!isFinite(trimmedStr)) { //Infinity return handleInfinity(str, Number(trimmedStr), options); } else if (trimmedStr.includes('e') || trimmedStr.includes('E')) { //eNotation return resolveEnotation(str, trimmedStr, options); } else { //separate negative sign, leading zeros, and rest number const match = numRegex.exec(trimmedStr); // +00.123 => [ , '+', '00', '.123', .. if (match) { const sign = match[1] || ""; const leadingZeros = match[2]; let numTrimmedByZeros = trimZeros(match[3]); //complete num without leading zeros const decimalAdjacentToLeadingZeros = sign ? // 0., -00., 000. str[leadingZeros.length + 1] === "." : str[leadingZeros.length] === "."; //trim ending zeros for floating number if (!options.leadingZeros //leading zeros are not allowed && (leadingZeros.length > 1 || (leadingZeros.length === 1 && !decimalAdjacentToLeadingZeros))) { // 00, 00.3, +03.24, 03, 03.24 return str; } else {//no leading zeros or leading zeros are allowed const num = Number(trimmedStr); const parsedStr = String(num); if (num === 0) return num; if (parsedStr.search(/[eE]/) !== -1) { //given number is long and parsed to eNotation if (options.eNotation) return num; else return str; } else if (trimmedStr.indexOf(".") !== -1) { //floating number if (parsedStr === "0") return num; //0.0 else if (parsedStr === numTrimmedByZeros) return num; //0.456. 0.79000 else if (parsedStr === `${sign}${numTrimmedByZeros}`) return num; else return str; } let n = leadingZeros ? numTrimmedByZeros : trimmedStr; if (leadingZeros) { // -009 => -9 return (n === parsedStr) || (sign + n === parsedStr) ? num : str } else { // +9 return (n === parsedStr) || (n === sign + parsedStr) ? num : str } } } else { //non-numeric string return str; } } } const eNotationRegx = /^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/; function resolveEnotation(str, trimmedStr, options) { if (!options.eNotation) return str; const notation = trimmedStr.match(eNotationRegx); if (notation) { let sign = notation[1] || ""; const eChar = notation[3].indexOf("e") === -1 ? "E" : "e"; const leadingZeros = notation[2]; const eAdjacentToLeadingZeros = sign ? // 0E. str[leadingZeros.length + 1] === eChar : str[leadingZeros.length] === eChar; if (leadingZeros.length > 1 && eAdjacentToLeadingZeros) return str; else if (leadingZeros.length === 1 && (notation[3].startsWith(`.${eChar}`) || notation[3][0] === eChar)) { return Number(trimmedStr); } else if (leadingZeros.length > 0) { // Has leading zeros — only accept if leadingZeros option allows it if (options.leadingZeros && !eAdjacentToLeadingZeros) { trimmedStr = (notation[1] || "") + notation[3]; return Number(trimmedStr); } else return str; } else { // No leading zeros — always valid e-notation, parse it return Number(trimmedStr); } } else { return str; } } /** * * @param {string} numStr without leading zeros * @returns */ function trimZeros(numStr) { if (numStr && numStr.indexOf(".") !== -1) {//float numStr = numStr.replace(/0+$/, ""); //remove ending zeros if (numStr === ".") numStr = "0"; else if (numStr[0] === ".") numStr = "0" + numStr; else if (numStr[numStr.length - 1] === ".") numStr = numStr.substring(0, numStr.length - 1); return numStr; } return numStr; } function parse_int(numStr, base) { const str = numStr.trim(); if (base === 2 || base === 8) numStr = str.substring(2); if (parseInt) return parseInt(numStr, base); else if (Number.parseInt) return Number.parseInt(numStr, base); else if (window && window.parseInt) return window.parseInt(numStr, base); else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported"); } /** * Handle infinite values based on user option * @param {string} str - original input string * @param {number} num - parsed number (Infinity or -Infinity) * @param {object} options - user options * @returns {string|number|null} based on infinity option */ function handleInfinity(str, num, options) { const isPositive = num === Infinity; switch (options.infinity.toLowerCase()) { case "null": return null; case "infinity": return num; // Return Infinity or -Infinity case "string": return isPositive ? "Infinity" : "-Infinity"; case "original": default: return str; // Return original string like "1e1000" } } function getIgnoreAttributesFn$1(ignoreAttributes) { if (typeof ignoreAttributes === 'function') { return ignoreAttributes } if (Array.isArray(ignoreAttributes)) { return (attrName) => { for (const pattern of ignoreAttributes) { if (typeof pattern === 'string' && attrName === pattern) { return true } if (pattern instanceof RegExp && pattern.test(attrName)) { return true } } } } return () => false } /** * Expression - Parses and stores a tag pattern expression * * Patterns are parsed once and stored in an optimized structure for fast matching. * * @example * const expr = new Expression("root.users.user"); * const expr2 = new Expression("..user[id]:first"); * const expr3 = new Expression("root/users/user", { separator: '/' }); */ class Expression { /** * Create a new Expression * @param {string} pattern - Pattern string (e.g., "root.users.user", "..user[id]") * @param {Object} options - Configuration options * @param {string} options.separator - Path separator (default: '.') */ constructor(pattern, options = {}, data) { this.pattern = pattern; this.separator = options.separator || '.'; this.segments = this._parse(pattern); this.data = data; // Cache expensive checks for performance (O(1) instead of O(n)) this._hasDeepWildcard = this.segments.some(seg => seg.type === 'deep-wildcard'); this._hasAttributeCondition = this.segments.some(seg => seg.attrName !== undefined); this._hasPositionSelector = this.segments.some(seg => seg.position !== undefined); } /** * Parse pattern string into segments * @private * @param {string} pattern - Pattern to parse * @returns {Array} Array of segment objects */ _parse(pattern) { const segments = []; // Split by separator but handle ".." specially let i = 0; let currentPart = ''; while (i < pattern.length) { if (pattern[i] === this.separator) { // Check if next char is also separator (deep wildcard) if (i + 1 < pattern.length && pattern[i + 1] === this.separator) { // Flush current part if any if (currentPart.trim()) { segments.push(this._parseSegment(currentPart.trim())); currentPart = ''; } // Add deep wildcard segments.push({ type: 'deep-wildcard' }); i += 2; // Skip both separators } else { // Regular separator if (currentPart.trim()) { segments.push(this._parseSegment(currentPart.trim())); } currentPart = ''; i++; } } else { currentPart += pattern[i]; i++; } } // Flush remaining part if (currentPart.trim()) { segments.push(this._parseSegment(currentPart.trim())); } return segments; } /** * Parse a single segment * @private * @param {string} part - Segment string (e.g., "user", "ns::user", "user[id]", "ns::user:first") * @returns {Object} Segment object */ _parseSegment(part) { const segment = { type: 'tag' }; // NEW NAMESPACE SYNTAX (v2.0): // ============================ // Namespace uses DOUBLE colon (::) // Position uses SINGLE colon (:) // // Examples: // "user" → tag // "user:first" → tag + position // "user[id]" → tag + attribute // "user[id]:first" → tag + attribute + position // "ns::user" → namespace + tag // "ns::user:first" → namespace + tag + position // "ns::user[id]" → namespace + tag + attribute // "ns::user[id]:first" → namespace + tag + attribute + position // "ns::first" → namespace + tag named "first" (NO ambiguity!) // // This eliminates all ambiguity: // :: = namespace separator // : = position selector // [] = attributes // Step 1: Extract brackets [attr] or [attr=value] let bracketContent = null; let withoutBrackets = part; const bracketMatch = part.match(/^([^\[]+)(\[[^\]]*\])(.*)$/); if (bracketMatch) { withoutBrackets = bracketMatch[1] + bracketMatch[3]; if (bracketMatch[2]) { const content = bracketMatch[2].slice(1, -1); if (content) { bracketContent = content; } } } // Step 2: Check for namespace (double colon ::) let namespace = undefined; let tagAndPosition = withoutBrackets; if (withoutBrackets.includes('::')) { const nsIndex = withoutBrackets.indexOf('::'); namespace = withoutBrackets.substring(0, nsIndex).trim(); tagAndPosition = withoutBrackets.substring(nsIndex + 2).trim(); // Skip :: if (!namespace) { throw new Error(`Invalid namespace in pattern: ${part}`); } } // Step 3: Parse tag and position (single colon :) let tag = undefined; let positionMatch = null; if (tagAndPosition.includes(':')) { const colonIndex = tagAndPosition.lastIndexOf(':'); // Use last colon for position const tagPart = tagAndPosition.substring(0, colonIndex).trim(); const posPart = tagAndPosition.substring(colonIndex + 1).trim(); // Verify position is a valid keyword const isPositionKeyword = ['first', 'last', 'odd', 'even'].includes(posPart) || /^nth\(\d+\)$/.test(posPart); if (isPositionKeyword) { tag = tagPart; positionMatch = posPart; } else { // Not a valid position keyword, treat whole thing as tag tag = tagAndPosition; } } else { tag = tagAndPosition; } if (!tag) { throw new Error(`Invalid segment pattern: ${part}`); } segment.tag = tag; if (namespace) { segment.namespace = namespace; } // Step 4: Parse attributes if (bracketContent) { if (bracketContent.includes('=')) { const eqIndex = bracketContent.indexOf('='); segment.attrName = bracketContent.substring(0, eqIndex).trim(); segment.attrValue = bracketContent.substring(eqIndex + 1).trim(); } else { segment.attrName = bracketContent.trim(); } } // Step 5: Parse position selector if (positionMatch) { const nthMatch = positionMatch.match(/^nth\((\d+)\)$/); if (nthMatch) { segment.position = 'nth'; segment.positionValue = parseInt(nthMatch[1], 10); } else { segment.position = positionMatch; } } return segment; } /** * Get the number of segments * @returns {number} */ get length() { return this.segments.length; } /** * Check if expression contains deep wildcard * @returns {boolean} */ hasDeepWildcard() { return this._hasDeepWildcard; } /** * Check if expression has attribute conditions * @returns {boolean} */ hasAttributeCondition() { return this._hasAttributeCondition; } /** * Check if expression has position selectors * @returns {boolean} */ hasPositionSelector() { return this._hasPositionSelector; } /** * Get string representation * @returns {string} */ toString() { return this.pattern; } } /** * ExpressionSet - An indexed collection of Expressions for efficient bulk matching * * Instead of iterating all expressions on every tag, ExpressionSet pre-indexes * them at insertion time by depth and terminal tag name. At match time, only * the relevant bucket is evaluated — typically reducing checks from O(E) to O(1) * lookup plus O(small bucket) matches. * * Three buckets are maintained: * - `_byDepthAndTag` — exact depth + exact tag name (tightest, used first) * - `_wildcardByDepth` — exact depth + wildcard tag `*` (depth-matched only) * - `_deepWildcards` — expressions containing `..` (cannot be depth-indexed) * * @example * import { Expression, ExpressionSet } from 'fast-xml-tagger'; * * // Build once at config time * const stopNodes = new ExpressionSet(); * stopNodes.add(new Expression('root.users.user')); * stopNodes.add(new Expression('root.config.setting')); * stopNodes.add(new Expression('..script')); * * // Query on every tag — hot path * if (stopNodes.matchesAny(matcher)) { ... } */ class ExpressionSet { constructor() { /** @type {Map} depth:tag → expressions */ this._byDepthAndTag = new Map(); /** @type {Map} depth → wildcard-tag expressions */ this._wildcardByDepth = new Map(); /** @type {import('./Expression.js').default[]} expressions containing deep wildcard (..) */ this._deepWildcards = []; /** @type {Set} pattern strings already added — used for deduplication */ this._patterns = new Set(); /** @type {boolean} whether the set is sealed against further additions */ this._sealed = false; } /** * Add an Expression to the set. * Duplicate patterns (same pattern string) are silently ignored. * * @param {import('./Expression.js').default} expression - A pre-constructed Expression instance * @returns {this} for chaining * @throws {TypeError} if called after seal() * * @example * set.add(new Expression('root.users.user')); * set.add(new Expression('..script')); */ add(expression) { if (this._sealed) { throw new TypeError( 'ExpressionSet is sealed. Create a new ExpressionSet to add more expressions.' ); } // Deduplicate by pattern string if (this._patterns.has(expression.pattern)) return this; this._patterns.add(expression.pattern); if (expression.hasDeepWildcard()) { this._deepWildcards.push(expression); return this; } const depth = expression.length; const lastSeg = expression.segments[expression.segments.length - 1]; const tag = lastSeg?.tag; if (!tag || tag === '*') { // Can index by depth but not by tag if (!this._wildcardByDepth.has(depth)) this._wildcardByDepth.set(depth, []); this._wildcardByDepth.get(depth).push(expression); } else { // Tightest bucket: depth + tag const key = `${depth}:${tag}`; if (!this._byDepthAndTag.has(key)) this._byDepthAndTag.set(key, []); this._byDepthAndTag.get(key).push(expression); } return this; } /** * Add multiple expressions at once. * * @param {import('./Expression.js').default[]} expressions - Array of Expression instances * @returns {this} for chaining * * @example * set.addAll([ * new Expression('root.users.user'), * new Expression('root.config.setting'), * ]); */ addAll(expressions) { for (const expr of expressions) this.add(expr); return this; } /** * Check whether a pattern string is already present in the set. * * @param {import('./Expression.js').default} expression * @returns {boolean} */ has(expression) { return this._patterns.has(expression.pattern); } /** * Number of expressions in the set. * @type {number} */ get size() { return this._patterns.size; } /** * Seal the set against further modifications. * Useful to prevent accidental mutations after config is built. * Calling add() or addAll() on a sealed set throws a TypeError. * * @returns {this} */ seal() { this._sealed = true; return this; } /** * Whether the set has been sealed. * @type {boolean} */ get isSealed() { return this._sealed; } /** * Test whether the matcher's current path matches any expression in the set. * * Evaluation order (cheapest → most expensive): * 1. Exact depth + tag bucket — O(1) lookup, typically 0–2 expressions * 2. Depth-only wildcard bucket — O(1) lookup, rare * 3. Deep-wildcard list — always checked, but usually small * * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view) * @returns {boolean} true if any expression matches the current path * * @example * if (stopNodes.matchesAny(matcher)) { * // handle stop node * } */ matchesAny(matcher) { return this.findMatch(matcher) !== null; } /** * Find and return the first Expression that matches the matcher's current path. * * Uses the same evaluation order as matchesAny (cheapest → most expensive): * 1. Exact depth + tag bucket * 2. Depth-only wildcard bucket * 3. Deep-wildcard list * * @param {import('./Matcher.js').default} matcher - Matcher instance (or readOnly view) * @returns {import('./Expression.js').default | null} the first matching Expression, or null * * @example * const expr = stopNodes.findMatch(matcher); * if (expr) { * // access expr.config, expr.pattern, etc. * } */ findMatch(matcher) { const depth = matcher.getDepth(); const tag = matcher.getCurrentTag(); // 1. Tightest bucket — most expressions live here const exactKey = `${depth}:${tag}`; const exactBucket = this._byDepthAndTag.get(exactKey); if (exactBucket) { for (let i = 0; i < exactBucket.length; i++) { if (matcher.matches(exactBucket[i])) return exactBucket[i]; } } // 2. Depth-matched wildcard-tag expressions const wildcardBucket = this._wildcardByDepth.get(depth); if (wildcardBucket) { for (let i = 0; i < wildcardBucket.length; i++) { if (matcher.matches(wildcardBucket[i])) return wildcardBucket[i]; } } // 3. Deep wildcards — cannot be pre-filtered by depth or tag for (let i = 0; i < this._deepWildcards.length; i++) { if (matcher.matches(this._deepWildcards[i])) return this._deepWildcards[i]; } return null; } } /** * MatcherView - A lightweight read-only view over a Matcher's internal state. * * Created once by Matcher and reused across all callbacks. Holds a direct * reference to the parent Matcher so it always reflects current parser state * with zero copying or freezing overhead. * * Users receive this via {@link Matcher#readOnly} or directly from parser * callbacks. It exposes all query and matching methods but has no mutation * methods — misuse is caught at the TypeScript level rather than at runtime. * * @example * const matcher = new Matcher(); * const view = matcher.readOnly(); * * matcher.push("root", {}); * view.getCurrentTag(); // "root" * view.getDepth(); // 1 */ class MatcherView { /** * @param {Matcher} matcher - The parent Matcher instance to read from. */ constructor(matcher) { this._matcher = matcher; } /** * Get the path separator used by the parent matcher. * @returns {string} */ get separator() { return this._matcher.separator; } /** * Get current tag name. * @returns {string|undefined} */ getCurrentTag() { const path = this._matcher.path; return path.length > 0 ? path[path.length - 1].tag : undefined; } /** * Get current namespace. * @returns {string|undefined} */ getCurrentNamespace() { const path = this._matcher.path; return path.length > 0 ? path[path.length - 1].namespace : undefined; } /** * Get current node's attribute value. * @param {string} attrName * @returns {*} */ getAttrValue(attrName) { const path = this._matcher.path; if (path.length === 0) return undefined; return path[path.length - 1].values?.[attrName]; } /** * Check if current node has an attribute. * @param {string} attrName * @returns {boolean} */ hasAttr(attrName) { const path = this._matcher.path; if (path.length === 0) return false; const current = path[path.length - 1]; return current.values !== undefined && attrName in current.values; } /** * Get current node's sibling position (child index in parent). * @returns {number} */ getPosition() { const path = this._matcher.path; if (path.length === 0) return -1; return path[path.length - 1].position ?? 0; } /** * Get current node's repeat counter (occurrence count of this tag name). * @returns {number} */ getCounter() { const path = this._matcher.path; if (path.length === 0) return -1; return path[path.length - 1].counter ?? 0; } /** * Get current node's sibling index (alias for getPosition). * @returns {number} * @deprecated Use getPosition() or getCounter() instead */ getIndex() { return this.getPosition(); } /** * Get current path depth. * @returns {number} */ getDepth() { return this._matcher.path.length; } /** * Get path as string. * @param {string} [separator] - Optional separator (uses default if not provided) * @param {boolean} [includeNamespace=true] * @returns {string} */ toString(separator, includeNamespace = true) { return this._matcher.toString(separator, includeNamespace); } /** * Get path as array of tag names. * @returns {string[]} */ toArray() { return this._matcher.path.map(n => n.tag); } /** * Match current path against an Expression. * @param {Expression} expression * @returns {boolean} */ matches(expression) { return this._matcher.matches(expression); } /** * Match any expression in the given set against the current path. * @param {ExpressionSet} exprSet * @returns {boolean} */ matchesAny(exprSet) { return exprSet.matchesAny(this._matcher); } } /** * Matcher - Tracks current path in XML/JSON tree and matches against Expressions. * * The matcher maintains a stack of nodes representing the current path from root to * current tag. It only stores attribute values for the current (top) node to minimize * memory usage. Sibling tracking is used to auto-calculate position and counter. * * Use {@link Matcher#readOnly} to obtain a {@link MatcherView} safe to pass to * user callbacks — it always reflects current state with no Proxy overhead. * * @example * const matcher = new Matcher(); * matcher.push("root", {}); * matcher.push("users", {}); * matcher.push("user", { id: "123", type: "admin" }); * * const expr = new Expression("root.users.user"); * matcher.matches(expr); // true */ class Matcher { /** * Create a new Matcher. * @param {Object} [options={}] * @param {string} [options.separator='.'] - Default path separator */ constructor(options = {}) { this.separator = options.separator || '.'; this.path = []; this.siblingStacks = []; // Each path node: { tag, values, position, counter, namespace? } // values only present for current (last) node // Each siblingStacks entry: Map tracking occurrences at each level this._pathStringCache = null; this._view = new MatcherView(this); } /** * Push a new tag onto the path. * @param {string} tagName * @param {Object|null} [attrValues=null] * @param {string|null} [namespace=null] */ push(tagName, attrValues = null, namespace = null) { this._pathStringCache = null; // Remove values from previous current node (now becoming ancestor) if (this.path.length > 0) { this.path[this.path.length - 1].values = undefined; } // Get or create sibling tracking for current level const currentLevel = this.path.length; if (!this.siblingStacks[currentLevel]) { this.siblingStacks[currentLevel] = new Map(); } const siblings = this.siblingStacks[currentLevel]; // Create a unique key for sibling tracking that includes namespace const siblingKey = namespace ? `${namespace}:${tagName}` : tagName; // Calculate counter (how many times this tag appeared at this level) const counter = siblings.get(siblingKey) || 0; // Calculate position (total children at this level so far) let position = 0; for (const count of siblings.values()) { position += count; } // Update sibling count for this tag siblings.set(siblingKey, counter + 1); // Create new node const node = { tag: tagName, position: position, counter: counter }; if (namespace !== null && namespace !== undefined) { node.namespace = namespace; } if (attrValues !== null && attrValues !== undefined) { node.values = attrValues; } this.path.push(node); } /** * Pop the last tag from the path. * @returns {Object|undefined} The popped node */ pop() { if (this.path.length === 0) return undefined; this._pathStringCache = null; const node = this.path.pop(); if (this.siblingStacks.length > this.path.length + 1) { this.siblingStacks.length = this.path.length + 1; } return node; } /** * Update current node's attribute values. * Useful when attributes are parsed after push. * @param {Object} attrValues */ updateCurrent(attrValues) { if (this.path.length > 0) { const current = this.path[this.path.length - 1]; if (attrValues !== null && attrValues !== undefined) { current.values = attrValues; } } } /** * Get current tag name. * @returns {string|undefined} */ getCurrentTag() { return this.path.length > 0 ? this.path[this.path.length - 1].tag : undefined; } /** * Get current namespace. * @returns {string|undefined} */ getCurrentNamespace() { return this.path.length > 0 ? this.path[this.path.length - 1].namespace : undefined; } /** * Get current node's attribute value. * @param {string} attrName * @returns {*} */ getAttrValue(attrName) { if (this.path.length === 0) return undefined; return this.path[this.path.length - 1].values?.[attrName]; } /** * Check if current node has an attribute. * @param {string} attrName * @returns {boolean} */ hasAttr(attrName) { if (this.path.length === 0) return false; const current = this.path[this.path.length - 1]; return current.values !== undefined && attrName in current.values; } /** * Get current node's sibling position (child index in parent). * @returns {number} */ getPosition() { if (this.path.length === 0) return -1; return this.path[this.path.length - 1].position ?? 0; } /** * Get current node's repeat counter (occurrence count of this tag name). * @returns {number} */ getCounter() { if (this.path.length === 0) return -1; return this.path[this.path.length - 1].counter ?? 0; } /** * Get current node's sibling index (alias for getPosition). * @returns {number} * @deprecated Use getPosition() or getCounter() instead */ getIndex() { return this.getPosition(); } /** * Get current path depth. * @returns {number} */ getDepth() { return this.path.length; } /** * Get path as string. * @param {string} [separator] - Optional separator (uses default if not provided) * @param {boolean} [includeNamespace=true] * @returns {string} */ toString(separator, includeNamespace = true) { const sep = separator || this.separator; const isDefault = (sep === this.separator && includeNamespace === true); if (isDefault) { if (this._pathStringCache !== null) { return this._pathStringCache; } const result = this.path.map(n => (n.namespace) ? `${n.namespace}:${n.tag}` : n.tag ).join(sep); this._pathStringCache = result; return result; } return this.path.map(n => (includeNamespace && n.namespace) ? `${n.namespace}:${n.tag}` : n.tag ).join(sep); } /** * Get path as array of tag names. * @returns {string[]} */ toArray() { return this.path.map(n => n.tag); } /** * Reset the path to empty. */ reset() { this._pathStringCache = null; this.path = []; this.siblingStacks = []; } /** * Match current path against an Expression. * @param {Expression} expression * @returns {boolean} */ matches(expression) { const segments = expression.segments; if (segments.length === 0) { return false; } if (expression.hasDeepWildcard()) { return this._matchWithDeepWildcard(segments); } return this._matchSimple(segments); } /** * @private */ _matchSimple(segments) { if (this.path.length !== segments.length) { return false; } for (let i = 0; i < segments.length; i++) { if (!this._matchSegment(segments[i], this.path[i], i === this.path.length - 1)) { return false; } } return true; } /** * @private */ _matchWithDeepWildcard(segments) { let pathIdx = this.path.length - 1; let segIdx = segments.length - 1; while (segIdx >= 0 && pathIdx >= 0) { const segment = segments[segIdx]; if (segment.type === 'deep-wildcard') { segIdx--; if (segIdx < 0) { return true; } const nextSeg = segments[segIdx]; let found = false; for (let i = pathIdx; i >= 0; i--) { if (this._matchSegment(nextSeg, this.path[i], i === this.path.length - 1)) { pathIdx = i - 1; segIdx--; found = true; break; } } if (!found) { return false; } } else { if (!this._matchSegment(segment, this.path[pathIdx], pathIdx === this.path.length - 1)) { return false; } pathIdx--; segIdx--; } } return segIdx < 0; } /** * @private */ _matchSegment(segment, node, isCurrentNode) { if (segment.tag !== '*' && segment.tag !== node.tag) { return false; } if (segment.namespace !== undefined) { if (segment.namespace !== '*' && segment.namespace !== node.namespace) { return false; } } if (segment.attrName !== undefined) { if (!isCurrentNode) { return false; } if (!node.values || !(segment.attrName in node.values)) { return false; } if (segment.attrValue !== undefined) { if (String(node.values[segment.attrName]) !== String(segment.attrValue)) { return false; } } } if (segment.position !== undefined) { if (!isCurrentNode) { return false; } const counter = node.counter ?? 0; if (segment.position === 'first' && counter !== 0) { return false; } else if (segment.position === 'odd' && counter % 2 !== 1) { return false; } else if (segment.position === 'even' && counter % 2 !== 0) { return false; } else if (segment.position === 'nth' && counter !== segment.positionValue) { return false; } } return true; } /** * Match any expression in the given set against the current path. * @param {ExpressionSet} exprSet * @returns {boolean} */ matchesAny(exprSet) { return exprSet.matchesAny(this); } /** * Create a snapshot of current state. * @returns {Object} */ snapshot() { return { path: this.path.map(node => ({ ...node })), siblingStacks: this.siblingStacks.map(map => new Map(map)) }; } /** * Restore state from snapshot. * @param {Object} snapshot */ restore(snapshot) { this._pathStringCache = null; this.path = snapshot.path.map(node => ({ ...node })); this.siblingStacks = snapshot.siblingStacks.map(map => new Map(map)); } /** * Return the read-only {@link MatcherView} for this matcher. * * The same instance is returned on every call — no allocation occurs. * It always reflects the current parser state and is safe to pass to * user callbacks without risk of accidental mutation. * * @returns {MatcherView} * * @example * const view = matcher.readOnly(); * // pass view to callbacks — it stays in sync automatically * view.matches(expr); // ✓ * view.getCurrentTag(); // ✓ * // view.push(...) // ✗ method does not exist — caught by TypeScript */ readOnly() { return this._view; } } // const regx = // '<((!\\[CDATA\\[([\\s\\S]*?)(]]>))|((NAME:)?(NAME))([^>]*)>|((\\/)(NAME)\\s*>))([^<]*)' // .replace(/NAME/g, util.nameRegexp); //const tagsRegx = new RegExp("<(\\/?[\\w:\\-\._]+)([^>]*)>(\\s*"+cdataRegx+")*([^<]+)?","g"); //const tagsRegx = new RegExp("<(\\/?)((\\w*:)?([\\w:\\-\._]+))([^>]*)>([^<]*)("+cdataRegx+"([^<]*))*([^<]+)?","g"); // Helper functions for attribute and namespace handling /** * Extract raw attributes (without prefix) from prefixed attribute map * @param {object} prefixedAttrs - Attributes with prefix from buildAttributesMap * @param {object} options - Parser options containing attributeNamePrefix * @returns {object} Raw attributes for matcher */ function extractRawAttributes(prefixedAttrs, options) { if (!prefixedAttrs) return {}; // Handle attributesGroupName option const attrs = options.attributesGroupName ? prefixedAttrs[options.attributesGroupName] : prefixedAttrs; if (!attrs) return {}; const rawAttrs = {}; for (const key in attrs) { // Remove the attribute prefix to get raw name if (key.startsWith(options.attributeNamePrefix)) { const rawName = key.substring(options.attributeNamePrefix.length); rawAttrs[rawName] = attrs[key]; } else { // Attribute without prefix (shouldn't normally happen, but be safe) rawAttrs[key] = attrs[key]; } } return rawAttrs; } /** * Extract namespace from raw tag name * @param {string} rawTagName - Tag name possibly with namespace (e.g., "soap:Envelope") * @returns {string|undefined} Namespace or undefined */ function extractNamespace(rawTagName) { if (!rawTagName || typeof rawTagName !== 'string') return undefined; const colonIndex = rawTagName.indexOf(':'); if (colonIndex !== -1 && colonIndex > 0) { const ns = rawTagName.substring(0, colonIndex); // Don't treat xmlns as a namespace if (ns !== 'xmlns') { return ns; } } return undefined; } class OrderedObjParser { constructor(options, externalEntities) { this.options = options; this.currentNode = null; this.tagsNodeStack = []; this.parseXml = parseXml; this.parseTextData = parseTextData; this.resolveNameSpace = resolveNameSpace; this.buildAttributesMap = buildAttributesMap; this.isItStopNode = isItStopNode; this.replaceEntitiesValue = replaceEntitiesValue$1; this.readStopNodeData = readStopNodeData; this.saveTextToParentTag = saveTextToParentTag; this.addChild = addChild; this.ignoreAttributesFn = getIgnoreAttributesFn$1(this.options.ignoreAttributes); this.entityExpansionCount = 0; this.currentExpandedLength = 0; let namedEntities = { ...XML }; if (this.options.entityDecoder) { this.entityDecoder = this.options.entityDecoder; } else { if (typeof this.options.htmlEntities === "object") namedEntities = this.options.htmlEntities; else if (this.options.htmlEntities === true) namedEntities = { ...COMMON_HTML, ...CURRENCY }; this.entityDecoder = new EntityDecoder({ namedEntities: { ...namedEntities, ...externalEntities }, numericAllowed: this.options.htmlEntities, limit: { maxTotalExpansions: this.options.processEntities.maxTotalExpansions, maxExpandedLength: this.options.processEntities.maxExpandedLength, applyLimitsTo: this.options.processEntities.appliesTo, } //postCheck: resolved => resolved }); } // Initialize path matcher for path-expression-matcher this.matcher = new Matcher(); this.readonlyMatcher = this.matcher.readOnly(); // Flag to track if current node is a stop node (optimization) this.isCurrentNodeStopNode = false; // Pre-compile stopNodes expressions this.stopNodeExpressionsSet = new ExpressionSet(); const stopNodesOpts = this.options.stopNodes; if (stopNodesOpts && stopNodesOpts.length > 0) { for (let i = 0; i < stopNodesOpts.length; i++) { const stopNodeExp = stopNodesOpts[i]; if (typeof stopNodeExp === 'string') { // Convert string to Expression object this.stopNodeExpressionsSet.add(new Expression(stopNodeExp)); } else if (stopNodeExp instanceof Expression) { // Already an Expression object this.stopNodeExpressionsSet.add(stopNodeExp); } } this.stopNodeExpressionsSet.seal(); } } } /** * @param {string} val * @param {string} tagName * @param {string|Matcher} jPath - jPath string or Matcher instance based on options.jPath * @param {boolean} dontTrim * @param {boolean} hasAttributes * @param {boolean} isLeafNode * @param {boolean} escapeEntities */ function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode, escapeEntities) { const options = this.options; if (val !== undefined) { if (options.trimValues && !dontTrim) { val = val.trim(); } if (val.length > 0) { if (!escapeEntities) val = this.replaceEntitiesValue(val, tagName, jPath); // Pass jPath string or matcher based on options.jPath setting const jPathOrMatcher = options.jPath ? jPath.toString() : jPath; const newval = options.tagValueProcessor(tagName, val, jPathOrMatcher, hasAttributes, isLeafNode); if (newval === null || newval === undefined) { //don't parse return val; } else if (typeof newval !== typeof val || newval !== val) { //overwrite return newval; } else if (options.trimValues) { return parseValue(val, options.parseTagValue, options.numberParseOptions); } else { const trimmedVal = val.trim(); if (trimmedVal === val) { return parseValue(val, options.parseTagValue, options.numberParseOptions); } else { return val; } } } } } function resolveNameSpace(tagname) { if (this.options.removeNSPrefix) { const tags = tagname.split(':'); const prefix = tagname.charAt(0) === '/' ? '/' : ''; if (tags[0] === 'xmlns') { return ''; } if (tags.length === 2) { tagname = prefix + tags[1]; } } return tagname; } //TODO: change regex to capture NS //const attrsRegx = new RegExp("([\\w\\-\\.\\:]+)\\s*=\\s*(['\"])((.|\n)*?)\\2","gm"); const attrsRegx = new RegExp('([^\\s=]+)\\s*(=\\s*([\'"])([\\s\\S]*?)\\3)?', 'gm'); function buildAttributesMap(attrStr, jPath, tagName, force = false) { const options = this.options; if (force === true || (options.ignoreAttributes !== true && typeof attrStr === 'string')) { // attrStr = attrStr.replace(/\r?\n/g, ' '); //attrStr = attrStr || attrStr.trim(); const matches = getAllMatches(attrStr, attrsRegx); const len = matches.length; //don't make it inline const attrs = {}; // Pre-process values once: trim + entity replacement // Reused in both matcher update and second pass const processedVals = new Array(len); let hasRawAttrs = false; const rawAttrsForMatcher = {}; for (let i = 0; i < len; i++) { const attrName = this.resolveNameSpace(matches[i][1]); const oldVal = matches[i][4]; if (attrName.length && oldVal !== undefined) { let val = oldVal; if (options.trimValues) val = val.trim(); val = this.replaceEntitiesValue(val, tagName, this.readonlyMatcher); processedVals[i] = val; rawAttrsForMatcher[attrName] = val; hasRawAttrs = true; } } // Update matcher ONCE before second pass, if applicable if (hasRawAttrs && typeof jPath === 'object' && jPath.updateCurrent) { jPath.updateCurrent(rawAttrsForMatcher); } // Hoist toString() once — path doesn't change during attribute processing const jPathStr = options.jPath ? jPath.toString() : this.readonlyMatcher; // Second pass: apply processors, build final attrs let hasAttrs = false; for (let i = 0; i < len; i++) { const attrName = this.resolveNameSpace(matches[i][1]); if (this.ignoreAttributesFn(attrName, jPathStr)) continue; let aName = options.attributeNamePrefix + attrName; if (attrName.length) { if (options.transformAttributeName) { aName = options.transformAttributeName(aName); } aName = sanitizeName(aName, options); if (matches[i][4] !== undefined) { // Reuse already-processed value — no double entity replacement const oldVal = processedVals[i]; const newVal = options.attributeValueProcessor(attrName, oldVal, jPathStr); if (newVal === null || newVal === undefined) { attrs[aName] = oldVal; } else if (typeof newVal !== typeof oldVal || newVal !== oldVal) { attrs[aName] = newVal; } else { attrs[aName] = parseValue(oldVal, options.parseAttributeValue, options.numberParseOptions); } hasAttrs = true; } else if (options.allowBooleanAttributes) { attrs[aName] = true; hasAttrs = true; } } } if (!hasAttrs) return; if (options.attributesGroupName && !options.preserveOrder) { const attrCollection = {}; attrCollection[options.attributesGroupName] = attrs; return attrCollection; } return attrs; } } const parseXml = function (xmlData) { xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line const xmlObj = new XmlNode('!xml'); let currentNode = xmlObj; let textData = ""; // Reset matcher for new document this.matcher.reset(); this.entityDecoder.reset(); // Reset entity expansion counters for this document this.entityExpansionCount = 0; this.currentExpandedLength = 0; const options = this.options; const docTypeReader = new DocTypeReader(options.processEntities); const xmlLen = xmlData.length; for (let i = 0; i < xmlLen; i++) {//for each char in XML data const ch = xmlData[i]; if (ch === '<') { // const nextIndex = i+1; // const _2ndChar = xmlData[nextIndex]; const c1 = xmlData.charCodeAt(i + 1); if (c1 === 47) {//Closing Tag '/' const closeIndex = findClosingIndex(xmlData, ">", i, "Closing Tag is not closed."); let tagName = xmlData.substring(i + 2, closeIndex).trim(); if (options.removeNSPrefix) { const colonIndex = tagName.indexOf(":"); if (colonIndex !== -1) { tagName = tagName.substr(colonIndex + 1); } } tagName = transformTagName(options.transformTagName, tagName, "", options).tagName; if (currentNode) { textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher); } //check if last tag of nested tag was unpaired tag const lastTagName = this.matcher.getCurrentTag(); if (tagName && options.unpairedTagsSet.has(tagName)) { throw new Error(`Unpaired tag can not be used as closing tag: `); } if (lastTagName && options.unpairedTagsSet.has(lastTagName)) { // Pop the unpaired tag this.matcher.pop(); this.tagsNodeStack.pop(); } // Pop the closing tag this.matcher.pop(); this.isCurrentNodeStopNode = false; // Reset flag when closing tag currentNode = this.tagsNodeStack.pop();//avoid recursion, set the parent tag scope textData = ""; i = closeIndex; } else if (c1 === 63) { //'?' let tagData = readTagExp(xmlData, i, false, "?>"); if (!tagData) throw new Error("Pi Tag is not closed."); textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher); const attsMap = this.buildAttributesMap(tagData.tagExp, this.matcher, tagData.tagName, true); if (attsMap) { const ver = attsMap[this.options.attributeNamePrefix + "version"]; this.entityDecoder.setXmlVersion(Number(ver) || 1.0); docTypeReader.setXmlVersion(Number(ver) || 1.0); } if ((options.ignoreDeclaration && tagData.tagName === "?xml") || options.ignorePiTags) ; else { const childNode = new XmlNode(tagData.tagName); childNode.add(options.textNodeName, ""); if (tagData.tagName !== tagData.tagExp && tagData.attrExpPresent && options.ignoreAttributes !== true) { childNode[":@"] = attsMap; } this.addChild(currentNode, childNode, this.readonlyMatcher, i); } i = tagData.closeIndex + 1; } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 45 && xmlData.charCodeAt(i + 3) === 45) { //'!--' const endIndex = findClosingIndex(xmlData, "-->", i + 4, "Comment is not closed."); if (options.commentPropName) { const comment = xmlData.substring(i + 4, endIndex - 2); textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher); currentNode.add(options.commentPropName, [{ [options.textNodeName]: comment }]); } i = endIndex; } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 68) { //'!D' const result = docTypeReader.readDocType(xmlData, i); this.entityDecoder.addInputEntities(result.entities); i = result.i; } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 91) { // '![' const closeIndex = findClosingIndex(xmlData, "]]>", i, "CDATA is not closed.") - 2; const tagExp = xmlData.substring(i + 9, closeIndex); textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher); let val = this.parseTextData(tagExp, currentNode.tagname, this.readonlyMatcher, true, false, true, true); if (val == undefined) val = ""; //cdata should be set even if it is 0 length string if (options.cdataPropName) { currentNode.add(options.cdataPropName, [{ [options.textNodeName]: tagExp }]); } else { currentNode.add(options.textNodeName, val); } i = closeIndex + 2; } else {//Opening tag let result = readTagExp(xmlData, i, options.removeNSPrefix); // Safety check: readTagExp can return undefined if (!result) { // Log context for debugging const context = xmlData.substring(Math.max(0, i - 50), Math.min(xmlLen, i + 50)); throw new Error(`readTagExp returned undefined at position ${i}. Context: "${context}"`); } let tagName = result.tagName; const rawTagName = result.rawTagName; let tagExp = result.tagExp; let attrExpPresent = result.attrExpPresent; let closeIndex = result.closeIndex; ({ tagName, tagExp } = transformTagName(options.transformTagName, tagName, tagExp, options)); if (options.strictReservedNames && (tagName === options.commentPropName || tagName === options.cdataPropName || tagName === options.textNodeName || tagName === options.attributesGroupName )) { throw new Error(`Invalid tag name: ${tagName}`); } //save text as child node if (currentNode && textData) { if (currentNode.tagname !== '!xml') { //when nested tag is found textData = this.saveTextToParentTag(textData, currentNode, this.readonlyMatcher, false); } } //check if last tag was unpaired tag const lastTag = currentNode; if (lastTag && options.unpairedTagsSet.has(lastTag.tagname)) { currentNode = this.tagsNodeStack.pop(); this.matcher.pop(); } // Clean up self-closing syntax BEFORE processing attributes // This is where tagExp gets the trailing / removed let isSelfClosing = false; if (tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1) { isSelfClosing = true; if (tagName[tagName.length - 1] === "/") { tagName = tagName.substr(0, tagName.length - 1); tagExp = tagName; } else { tagExp = tagExp.substr(0, tagExp.length - 1); } // Re-check attrExpPresent after cleaning attrExpPresent = (tagName !== tagExp); } // Now process attributes with CLEAN tagExp (no trailing /) let prefixedAttrs = null; let namespace = undefined; // Extract namespace from rawTagName namespace = extractNamespace(rawTagName); // Push tag to matcher FIRST (with empty attrs for now) so callbacks see correct path if (tagName !== xmlObj.tagname) { this.matcher.push(tagName, {}, namespace); } // Now build attributes - callbacks will see correct matcher state if (tagName !== tagExp && attrExpPresent) { // Build attributes (returns prefixed attributes for the tree) // Note: buildAttributesMap now internally updates the matcher with raw attributes prefixedAttrs = this.buildAttributesMap(tagExp, this.matcher, tagName); if (prefixedAttrs) { // Extract raw attributes (without prefix) for our use //TODO: seems a performance overhead extractRawAttributes(prefixedAttrs, options); } } // Now check if this is a stop node (after attributes are set) if (tagName !== xmlObj.tagname) { this.isCurrentNodeStopNode = this.isItStopNode(); } const startIndex = i; if (this.isCurrentNodeStopNode) { let tagContent = ""; // For self-closing tags, content is empty if (isSelfClosing) { i = result.closeIndex; } //unpaired tag else if (options.unpairedTagsSet.has(tagName)) { i = result.closeIndex; } //normal tag else { //read until closing tag is found const result = this.readStopNodeData(xmlData, rawTagName, closeIndex + 1); if (!result) throw new Error(`Unexpected end of ${rawTagName}`); i = result.i; tagContent = result.tagContent; } const childNode = new XmlNode(tagName); if (prefixedAttrs) { childNode[":@"] = prefixedAttrs; } // For stop nodes, store raw content as-is without any processing childNode.add(options.textNodeName, tagContent); this.matcher.pop(); // Pop the stop node tag this.isCurrentNodeStopNode = false; // Reset flag this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex); } else { //selfClosing tag if (isSelfClosing) { ({ tagName, tagExp } = transformTagName(options.transformTagName, tagName, tagExp, options)); const childNode = new XmlNode(tagName); if (prefixedAttrs) { childNode[":@"] = prefixedAttrs; } this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex); this.matcher.pop(); // Pop self-closing tag this.isCurrentNodeStopNode = false; // Reset flag } else if (options.unpairedTagsSet.has(tagName)) {//unpaired tag const childNode = new XmlNode(tagName); if (prefixedAttrs) { childNode[":@"] = prefixedAttrs; } this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex); this.matcher.pop(); // Pop unpaired tag this.isCurrentNodeStopNode = false; // Reset flag i = result.closeIndex; // Continue to next iteration without changing currentNode continue; } //opening tag else { const childNode = new XmlNode(tagName); if (this.tagsNodeStack.length > options.maxNestedTags) { throw new Error("Maximum nested tags exceeded"); } this.tagsNodeStack.push(currentNode); if (prefixedAttrs) { childNode[":@"] = prefixedAttrs; } this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex); currentNode = childNode; } textData = ""; i = closeIndex; } } } else { textData += xmlData[i]; } } return xmlObj.child; }; function addChild(currentNode, childNode, matcher, startIndex) { // unset startIndex if not requested if (!this.options.captureMetaData) startIndex = undefined; // Pass jPath string or matcher based on options.jPath setting const jPathOrMatcher = this.options.jPath ? matcher.toString() : matcher; const result = this.options.updateTag(childNode.tagname, jPathOrMatcher, childNode[":@"]); if (result === false) ; else if (typeof result === "string") { childNode.tagname = result; currentNode.addChild(childNode, startIndex); } else { currentNode.addChild(childNode, startIndex); } } /** * @param {object} val - Entity object with regex and val properties * @param {string} tagName - Tag name * @param {string|Matcher} jPath - jPath string or Matcher instance based on options.jPath */ function replaceEntitiesValue$1(val, tagName, jPath) { const entityConfig = this.options.processEntities; if (!entityConfig || !entityConfig.enabled) { return val; } // Check if tag is allowed to contain entities if (entityConfig.allowedTags) { const jPathOrMatcher = this.options.jPath ? jPath.toString() : jPath; const allowed = Array.isArray(entityConfig.allowedTags) ? entityConfig.allowedTags.includes(tagName) : entityConfig.allowedTags(tagName, jPathOrMatcher); if (!allowed) { return val; } } // Apply custom tag filter if provided if (entityConfig.tagFilter) { const jPathOrMatcher = this.options.jPath ? jPath.toString() : jPath; if (!entityConfig.tagFilter(tagName, jPathOrMatcher)) { return val; // Skip based on custom filter } } return this.entityDecoder.decode(val); } function saveTextToParentTag(textData, parentNode, matcher, isLeafNode) { if (textData) { //store previously collected data as textNode if (isLeafNode === undefined) isLeafNode = parentNode.child.length === 0; textData = this.parseTextData(textData, parentNode.tagname, matcher, false, parentNode[":@"] ? Object.keys(parentNode[":@"]).length !== 0 : false, isLeafNode); if (textData !== undefined && textData !== "") parentNode.add(this.options.textNodeName, textData); textData = ""; } return textData; } /** * @param {Array} stopNodeExpressions - Array of compiled Expression objects * @param {Matcher} matcher - Current path matcher */ function isItStopNode() { if (this.stopNodeExpressionsSet.size === 0) return false; return this.matcher.matchesAny(this.stopNodeExpressionsSet); } /** * Returns the tag Expression and where it is ending handling single-double quotes situation * @param {string} xmlData * @param {number} i starting index * @returns */ function tagExpWithClosingIndex(xmlData, i, closingChar = ">") { //TODO: ignore boolean attributes in tag expression //TODO: if ignore attributes, dont read full attribute expression but the end. But read for xml declaration let attrBoundary = 0; const len = xmlData.length; const closeCode0 = closingChar.charCodeAt(0); const closeCode1 = closingChar.length > 1 ? closingChar.charCodeAt(1) : -1; let result = ''; let segmentStart = i; for (let index = i; index < len; index++) { const code = xmlData.charCodeAt(index); if (attrBoundary) { if (code === attrBoundary) attrBoundary = 0; } else if (code === 34 || code === 39) { // " or ' attrBoundary = code; } else if (code === closeCode0) { if (closeCode1 !== -1) { if (xmlData.charCodeAt(index + 1) === closeCode1) { result += xmlData.substring(segmentStart, index); return { data: result, index }; } } else { result += xmlData.substring(segmentStart, index); return { data: result, index }; } } else if (code === 9 && !attrBoundary) { // \t - only replace with space outside attribute values // Flush accumulated segment, add space, start new segment result += xmlData.substring(segmentStart, index) + ' '; segmentStart = index + 1; } } } function findClosingIndex(xmlData, str, i, errMsg) { const closingIndex = xmlData.indexOf(str, i); if (closingIndex === -1) { throw new Error(errMsg) } else { return closingIndex + str.length - 1; } } function findClosingChar(xmlData, char, i, errMsg) { const closingIndex = xmlData.indexOf(char, i); if (closingIndex === -1) throw new Error(errMsg); return closingIndex; // no offset needed } function readTagExp(xmlData, i, removeNSPrefix, closingChar = ">") { const result = tagExpWithClosingIndex(xmlData, i + 1, closingChar); if (!result) return; let tagExp = result.data; const closeIndex = result.index; const separatorIndex = tagExp.search(/\s/); let tagName = tagExp; let attrExpPresent = true; if (separatorIndex !== -1) {//separate tag name and attributes expression tagName = tagExp.substring(0, separatorIndex); tagExp = tagExp.substring(separatorIndex + 1).trimStart(); } const rawTagName = tagName; if (removeNSPrefix) { const colonIndex = tagName.indexOf(":"); if (colonIndex !== -1) { tagName = tagName.substr(colonIndex + 1); attrExpPresent = tagName !== result.data.substr(colonIndex + 1); } } return { tagName: tagName, tagExp: tagExp, closeIndex: closeIndex, attrExpPresent: attrExpPresent, rawTagName: rawTagName, } } /** * find paired tag for a stop node * @param {string} xmlData * @param {string} tagName * @param {number} i */ function readStopNodeData(xmlData, tagName, i) { const startIndex = i; // Starting at 1 since we already have an open tag let openTagCount = 1; const xmllen = xmlData.length; for (; i < xmllen; i++) { if (xmlData[i] === "<") { const c1 = xmlData.charCodeAt(i + 1); if (c1 === 47) {//close tag '/' const closeIndex = findClosingChar(xmlData, ">", i, `${tagName} is not closed`); let closeTagName = xmlData.substring(i + 2, closeIndex).trim(); if (closeTagName === tagName) { openTagCount--; if (openTagCount === 0) { return { tagContent: xmlData.substring(startIndex, i), i: closeIndex } } } i = closeIndex; } else if (c1 === 63) { //? const closeIndex = findClosingIndex(xmlData, "?>", i + 1, "StopNode is not closed."); i = closeIndex; } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 45 && xmlData.charCodeAt(i + 3) === 45) { // '!--' const closeIndex = findClosingIndex(xmlData, "-->", i + 3, "StopNode is not closed."); i = closeIndex; } else if (c1 === 33 && xmlData.charCodeAt(i + 2) === 91) { // '![' const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2; i = closeIndex; } else { const tagData = readTagExp(xmlData, i, false); if (tagData) { const openTagName = tagData && tagData.tagName; if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length - 1] !== "/") { openTagCount++; } i = tagData.closeIndex; } } } }//end for loop } function parseValue(val, shouldParse, options) { if (shouldParse && typeof val === 'string') { //console.log(options) const newval = val.trim(); if (newval === 'true') return true; else if (newval === 'false') return false; else return toNumber(val, options); } else { if (isExist(val)) { return val; } else { return ''; } } } function transformTagName(fn, tagName, tagExp, options) { if (fn) { const newTagName = fn(tagName); if (tagExp === tagName) { tagExp = newTagName; } tagName = newTagName; } tagName = sanitizeName(tagName, options); return { tagName, tagExp }; } function sanitizeName(name, options) { if (criticalProperties.includes(name)) { throw new Error(`[SECURITY] Invalid name: "${name}" is a reserved JavaScript keyword that could cause prototype pollution`); } else if (DANGEROUS_PROPERTY_NAMES.includes(name)) { return options.onDangerousProperty(name); } return name; } const METADATA_SYMBOL = XmlNode.getMetaDataSymbol(); /** * Helper function to strip attribute prefix from attribute map * @param {object} attrs - Attributes with prefix (e.g., {"@_class": "code"}) * @param {string} prefix - Attribute prefix to remove (e.g., "@_") * @returns {object} Attributes without prefix (e.g., {"class": "code"}) */ function stripAttributePrefix(attrs, prefix) { if (!attrs || typeof attrs !== 'object') return {}; if (!prefix) return attrs; const rawAttrs = {}; for (const key in attrs) { if (key.startsWith(prefix)) { const rawName = key.substring(prefix.length); rawAttrs[rawName] = attrs[key]; } else { // Attribute without prefix (shouldn't normally happen, but be safe) rawAttrs[key] = attrs[key]; } } return rawAttrs; } /** * * @param {array} node * @param {any} options * @param {Matcher} matcher - Path matcher instance * @returns */ function prettify(node, options, matcher, readonlyMatcher) { return compress(node, options, matcher, readonlyMatcher); } /** * @param {array} arr * @param {object} options * @param {Matcher} matcher - Path matcher instance * @returns object */ function compress(arr, options, matcher, readonlyMatcher) { let text; const compressedObj = {}; //This is intended to be a plain object for (let i = 0; i < arr.length; i++) { const tagObj = arr[i]; const property = propName$1(tagObj); // Push current property to matcher WITH RAW ATTRIBUTES (no prefix) if (property !== undefined && property !== options.textNodeName) { const rawAttrs = stripAttributePrefix( tagObj[":@"] || {}, options.attributeNamePrefix ); matcher.push(property, rawAttrs); } if (property === options.textNodeName) { if (text === undefined) text = tagObj[property]; else text += "" + tagObj[property]; } else if (property === undefined) { continue; } else if (tagObj[property]) { let val = compress(tagObj[property], options, matcher, readonlyMatcher); const isLeaf = isLeafTag(val, options); if (Object.keys(val).length === 0 && options.alwaysCreateTextNode) { val[options.textNodeName] = ""; } if (tagObj[":@"]) { assignAttributes(val, tagObj[":@"], readonlyMatcher, options); } else if (Object.keys(val).length === 1 && val[options.textNodeName] !== undefined && !options.alwaysCreateTextNode) { val = val[options.textNodeName]; } else if (Object.keys(val).length === 0) { if (options.alwaysCreateTextNode) val[options.textNodeName] = ""; else val = ""; } if (tagObj[METADATA_SYMBOL] !== undefined && typeof val === "object" && val !== null) { val[METADATA_SYMBOL] = tagObj[METADATA_SYMBOL]; // copy over metadata } if (compressedObj[property] !== undefined && Object.prototype.hasOwnProperty.call(compressedObj, property)) { if (!Array.isArray(compressedObj[property])) { compressedObj[property] = [compressedObj[property]]; } compressedObj[property].push(val); } else { //TODO: if a node is not an array, then check if it should be an array //also determine if it is a leaf node // Pass jPath string or readonlyMatcher based on options.jPath setting const jPathOrMatcher = options.jPath ? readonlyMatcher.toString() : readonlyMatcher; if (options.isArray(property, jPathOrMatcher, isLeaf)) { compressedObj[property] = [val]; } else { compressedObj[property] = val; } } // Pop property from matcher after processing if (property !== undefined && property !== options.textNodeName) { matcher.pop(); } } } // if(text && text.length > 0) compressedObj[options.textNodeName] = text; if (typeof text === "string") { if (text.length > 0) compressedObj[options.textNodeName] = text; } else if (text !== undefined) compressedObj[options.textNodeName] = text; return compressedObj; } function propName$1(obj) { const keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { const key = keys[i]; if (key !== ":@") return key; } } function assignAttributes(obj, attrMap, readonlyMatcher, options) { if (attrMap) { const keys = Object.keys(attrMap); const len = keys.length; //don't make it inline for (let i = 0; i < len; i++) { const atrrName = keys[i]; // This is the PREFIXED name (e.g., "@_class") // Strip prefix for matcher path (for isArray callback) const rawAttrName = atrrName.startsWith(options.attributeNamePrefix) ? atrrName.substring(options.attributeNamePrefix.length) : atrrName; // For attributes, we need to create a temporary path // Pass jPath string or matcher based on options.jPath setting const jPathOrMatcher = options.jPath ? readonlyMatcher.toString() + "." + rawAttrName : readonlyMatcher; if (options.isArray(atrrName, jPathOrMatcher, true, true)) { obj[atrrName] = [attrMap[atrrName]]; } else { obj[atrrName] = attrMap[atrrName]; } } } } function isLeafTag(obj, options) { const { textNodeName } = options; const propCount = Object.keys(obj).length; if (propCount === 0) { return true; } if ( propCount === 1 && (obj[textNodeName] || typeof obj[textNodeName] === "boolean" || obj[textNodeName] === 0) ) { return true; } return false; } class XMLParser { constructor(options) { this.externalEntities = {}; this.options = buildOptions(options); } /** * Parse XML dats to JS object * @param {string|Uint8Array} xmlData * @param {boolean|Object} validationOption */ parse(xmlData, validationOption) { if (typeof xmlData !== "string" && xmlData.toString) { xmlData = xmlData.toString(); } else if (typeof xmlData !== "string") { throw new Error("XML data is accepted in String or Bytes[] form.") } if (validationOption) { if (validationOption === true) validationOption = {}; //validate with default options const result = validate(xmlData, validationOption); if (result !== true) { throw Error(`${result.err.msg}:${result.err.line}:${result.err.col}`) } } const orderedObjParser = new OrderedObjParser(this.options, this.externalEntities); // orderedObjParser.entityDecoder.setExternalEntities(this.externalEntities); const orderedResult = orderedObjParser.parseXml(xmlData); if (this.options.preserveOrder || orderedResult === undefined) return orderedResult; else return prettify(orderedResult, this.options, orderedObjParser.matcher, orderedObjParser.readonlyMatcher); } /** * Add Entity which is not by default supported by this library * @param {string} key * @param {string} value */ addEntity(key, value) { if (value.indexOf("&") !== -1) { throw new Error("Entity value can't have '&'") } else if (key.indexOf("&") !== -1 || key.indexOf(";") !== -1) { throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for ' '") } else if (value === "&") { throw new Error("An entity with value '&' is not permitted"); } else { this.externalEntities[key] = value; } } /** * Returns a Symbol that can be used to access the metadata * property on a node. * * If Symbol is not available in the environment, an ordinary property is used * and the name of the property is here returned. * * The XMLMetaData property is only present when `captureMetaData` * is true in the options. */ static getMetaDataSymbol() { return XmlNode.getMetaDataSymbol(); } } function safeComment(val) { return String(val) .replace(/--/g, '- -') // -- is illegal anywhere in comment content .replace(/--/g, '- -') // handle the scenario when 2 consiucative dashes appears .replace(/-$/, '- '); // trailing - would form -- with the closing --> } function safeCdata(val) { return String(val).replace(/\]\]>/g, ']]]]>') } function escapeAttribute(val) { return String(val).replace(/"/g, '"').replace(/'/g, ''') } const EOL = "\n"; /** * Detect XML version from the first element of the ordered array input. * The first element must be a ?xml processing instruction with a version attribute. * Returns '1.0' if not found. * * @param {array} jArray * @param {object} options */ function detectXmlVersionFromArray(jArray, options) { if (!Array.isArray(jArray) || jArray.length === 0) return '1.0'; const first = jArray[0]; const firstKey = propName(first); if (firstKey === '?xml') { const attrs = first[':@']; if (attrs) { const versionKey = options.attributeNamePrefix + 'version'; if (attrs[versionKey]) return attrs[versionKey]; } } return '1.0'; } /** * Resolve a tag or attribute name through sanitizeName if configured. * Validation via xml-naming's qName is performed first; the sanitizeName * callback is invoked only when the name is invalid. If sanitizeName is * false (default), no validation occurs and the name is used as-is. * * @param {string} name - raw name from the JS object * @param {boolean} isAttribute - true when resolving an attribute name * @param {object} options * @param {Matcher} matcher - current matcher state (readonly from callback perspective) * @param {string} xmlVersion - '1.0' or '1.1', forwarded to xml-naming */ function resolveTagName$1(name, isAttribute, options, matcher, xmlVersion) { if (!options.sanitizeName) return name; if (qName(name, { xmlVersion })) return name; return options.sanitizeName(name, { isAttribute, matcher: matcher.readOnly() }); } /** * @param {array} jArray * @param {any} options * @returns */ function toXml(jArray, options) { let indentation = ""; if (options.format) { indentation = EOL; } // Pre-compile stopNode expressions for pattern matching const stopNodeExpressions = []; if (options.stopNodes && Array.isArray(options.stopNodes)) { for (let i = 0; i < options.stopNodes.length; i++) { const node = options.stopNodes[i]; if (typeof node === 'string') { stopNodeExpressions.push(new Expression(node)); } else if (node instanceof Expression) { stopNodeExpressions.push(node); } } } // Detect XML version for use in name validation const xmlVersion = detectXmlVersionFromArray(jArray, options); // Initialize matcher for path tracking const matcher = new Matcher(); return arrToStr(jArray, options, indentation, matcher, stopNodeExpressions, xmlVersion); } function arrToStr(arr, options, indentation, matcher, stopNodeExpressions, xmlVersion) { let xmlStr = ""; let isPreviousElementTag = false; if (options.maxNestedTags && matcher.getDepth() > options.maxNestedTags) { throw new Error("Maximum nested tags exceeded"); } if (!Array.isArray(arr)) { // Non-array values (e.g. string tag values) should be treated as text content if (arr !== undefined && arr !== null) { let text = arr.toString(); text = replaceEntitiesValue(text, options); return text; } return ""; } for (let i = 0; i < arr.length; i++) { const tagObj = arr[i]; const rawTagName = propName(tagObj); if (rawTagName === undefined) continue; // Special names are exempt from sanitizeName: internal conventions and PI tags // are not user-supplied XML element names. const isSpecialName = rawTagName === options.textNodeName || rawTagName === options.cdataPropName || rawTagName === options.commentPropName || rawTagName[0] === '?'; // Resolve tag name (may transform it; may throw for invalid names) const tagName = isSpecialName ? rawTagName : resolveTagName$1(rawTagName, false, options, matcher, xmlVersion); // Extract attributes from ":@" property const attrValues = extractAttributeValues(tagObj[":@"], options); // Push resolved tag to matcher WITH attributes matcher.push(tagName, attrValues); // Check if this is a stop node using Expression matching const isStopNode = checkStopNode(matcher, stopNodeExpressions); if (tagName === options.textNodeName) { let tagText = tagObj[rawTagName]; if (!isStopNode) { tagText = options.tagValueProcessor(tagName, tagText); tagText = replaceEntitiesValue(tagText, options); } if (isPreviousElementTag) { xmlStr += indentation; } xmlStr += tagText; isPreviousElementTag = false; matcher.pop(); continue; } else if (tagName === options.cdataPropName) { if (isPreviousElementTag) { xmlStr += indentation; } const val = tagObj[rawTagName][0][options.textNodeName]; const safeVal = safeCdata(val); xmlStr += ``; isPreviousElementTag = false; matcher.pop(); continue; } else if (tagName === options.commentPropName) { const val = tagObj[rawTagName][0][options.textNodeName]; const safeVal = safeComment(val); xmlStr += indentation + ``; isPreviousElementTag = true; matcher.pop(); continue; } else if (tagName[0] === "?") { const attStr = attr_to_str(tagObj[":@"], options, isStopNode, matcher, xmlVersion); const tempInd = tagName === "?xml" ? "" : indentation; // Text node content on PI/XML declaration tags is intentionally ignored. // Only attributes are valid on these tags per the XML spec. xmlStr += tempInd + `<${tagName}${attStr}?>`; isPreviousElementTag = true; matcher.pop(); continue; } let newIdentation = indentation; if (newIdentation !== "") { newIdentation += options.indentBy; } // Pass isStopNode to attr_to_str so attributes are also not processed for stopNodes const attStr = attr_to_str(tagObj[":@"], options, isStopNode, matcher, xmlVersion); const tagStart = indentation + `<${tagName}${attStr}`; // If this is a stopNode, get raw content without processing let tagValue; if (isStopNode) { tagValue = getRawContent(tagObj[rawTagName], options); } else { tagValue = arrToStr(tagObj[rawTagName], options, newIdentation, matcher, stopNodeExpressions, xmlVersion); } if (options.unpairedTags.indexOf(tagName) !== -1) { if (options.suppressUnpairedNode) xmlStr += tagStart + ">"; else xmlStr += tagStart + "/>"; } else if ((!tagValue || tagValue.length === 0) && options.suppressEmptyNode) { xmlStr += tagStart + "/>"; } else if (tagValue && tagValue.endsWith(">")) { xmlStr += tagStart + `>${tagValue}${indentation}`; } else { xmlStr += tagStart + ">"; if (tagValue && indentation !== "" && (tagValue.includes("/>") || tagValue.includes("`; } isPreviousElementTag = true; // Pop tag from matcher matcher.pop(); } return xmlStr; } /** * Extract attribute values from the ":@" object and return as plain object * for passing to matcher.push() */ function extractAttributeValues(attrMap, options) { if (!attrMap || options.ignoreAttributes) return null; const attrValues = {}; let hasAttrs = false; for (let attr in attrMap) { if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue; // Remove the attribute prefix to get clean attribute name const cleanAttrName = attr.startsWith(options.attributeNamePrefix) ? attr.substr(options.attributeNamePrefix.length) : attr; attrValues[cleanAttrName] = escapeAttribute(attrMap[attr]); hasAttrs = true; } return hasAttrs ? attrValues : null; } /** * Extract raw content from a stopNode without any processing * This preserves the content exactly as-is, including special characters */ function getRawContent(arr, options) { if (!Array.isArray(arr)) { // Non-array values return as-is if (arr !== undefined && arr !== null) { return arr.toString(); } return ""; } let content = ""; for (let i = 0; i < arr.length; i++) { const item = arr[i]; const tagName = propName(item); if (tagName === options.textNodeName) { // Raw text content - NO processing, NO entity replacement content += item[tagName]; } else if (tagName === options.cdataPropName) { // CDATA content content += item[tagName][0][options.textNodeName]; } else if (tagName === options.commentPropName) { // Comment content content += item[tagName][0][options.textNodeName]; } else if (tagName && tagName[0] === "?") { // Processing instruction - skip for stopNodes continue; } else if (tagName) { // Nested tags within stopNode — no sanitizeName, content is raw const attStr = attr_to_str_raw(item[":@"], options); const nestedContent = getRawContent(item[tagName], options); if (!nestedContent || nestedContent.length === 0) { content += `<${tagName}${attStr}/>`; } else { content += `<${tagName}${attStr}>${nestedContent}`; } } } return content; } /** * Build attribute string for stopNodes - NO entity replacement */ function attr_to_str_raw(attrMap, options) { let attrStr = ""; if (attrMap && !options.ignoreAttributes) { for (let attr in attrMap) { if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue; // For stopNodes, use raw value without processing let attrVal = attrMap[attr]; if (attrVal === true && options.suppressBooleanAttributes) { attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`; } else { attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${escapeAttribute(attrVal)}"`; } } } return attrStr; } function propName(obj) { const keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { const key = keys[i]; if (!Object.prototype.hasOwnProperty.call(obj, key)) continue; if (key !== ":@") return key; } } /** * Build attribute string, resolving attribute names through sanitizeName when configured. * Accepts matcher so the callback has path context. */ function attr_to_str(attrMap, options, isStopNode, matcher, xmlVersion) { let attrStr = ""; if (attrMap && !options.ignoreAttributes) { for (let attr in attrMap) { if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue; // Strip prefix to get the clean XML attribute name, then optionally sanitize it const cleanAttrName = attr.substr(options.attributeNamePrefix.length); const resolvedAttrName = isStopNode ? cleanAttrName // stopNodes are raw — skip sanitizeName for attr names too : resolveTagName$1(cleanAttrName, true, options, matcher, xmlVersion); let attrVal; if (isStopNode) { // For stopNodes, use raw value without any processing attrVal = attrMap[attr]; } else { // Normal processing: apply attributeValueProcessor and entity replacement attrVal = options.attributeValueProcessor(attr, attrMap[attr]); attrVal = replaceEntitiesValue(attrVal, options); } if (attrVal === true && options.suppressBooleanAttributes) { attrStr += ` ${resolvedAttrName}`; } else { attrStr += ` ${resolvedAttrName}="${escapeAttribute(attrVal)}"`; } } } return attrStr; } function checkStopNode(matcher, stopNodeExpressions) { if (!stopNodeExpressions || stopNodeExpressions.length === 0) return false; for (let i = 0; i < stopNodeExpressions.length; i++) { if (matcher.matches(stopNodeExpressions[i])) { return true; } } return false; } function replaceEntitiesValue(textValue, options) { if (textValue && textValue.length > 0 && options.processEntities) { for (let i = 0; i < options.entities.length; i++) { const entity = options.entities[i]; textValue = textValue.replace(entity.regex, entity.val); } } return textValue; } function getIgnoreAttributesFn(ignoreAttributes) { if (typeof ignoreAttributes === 'function') { return ignoreAttributes } if (Array.isArray(ignoreAttributes)) { return (attrName) => { for (const pattern of ignoreAttributes) { if (typeof pattern === 'string' && attrName === pattern) { return true } if (pattern instanceof RegExp && pattern.test(attrName)) { return true } } } } return () => false } const defaultOptions = { attributeNamePrefix: '@_', attributesGroupName: false, textNodeName: '#text', ignoreAttributes: true, cdataPropName: false, format: false, indentBy: ' ', suppressEmptyNode: false, suppressUnpairedNode: true, suppressBooleanAttributes: true, tagValueProcessor: function (key, a) { return a; }, attributeValueProcessor: function (attrName, a) { return a; }, preserveOrder: false, commentPropName: false, unpairedTags: [], entities: [ { regex: new RegExp("&", "g"), val: "&" },//it must be on top { regex: new RegExp(">", "g"), val: ">" }, { regex: new RegExp("<", "g"), val: "<" }, { regex: new RegExp("\'", "g"), val: "'" }, { regex: new RegExp("\"", "g"), val: """ } ], processEntities: true, stopNodes: [], // transformTagName: false, // transformAttributeName: false, oneListGroup: false, maxNestedTags: 100, jPath: true, // When true, callbacks receive string jPath; when false, receive Matcher instance sanitizeName: false // false = allow all names as-is (default, backward-compatible). // Set to a function (name, { isAttribute, matcher }) => string to // validate/sanitize tag and attribute names. Throw inside the function // to reject an invalid name. }; function Builder(options) { this.options = Object.assign({}, defaultOptions, options); // Convert old-style stopNodes for backward compatibility // Old syntax: "*.tag" meant "tag anywhere in tree" // New syntax: "..tag" means "tag anywhere in tree" if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) { this.options.stopNodes = this.options.stopNodes.map(node => { if (typeof node === 'string' && node.startsWith('*.')) { // Convert old wildcard syntax to deep wildcard return '..' + node.substring(2); } return node; }); } // Pre-compile stopNode expressions for pattern matching this.stopNodeExpressions = []; if (this.options.stopNodes && Array.isArray(this.options.stopNodes)) { for (let i = 0; i < this.options.stopNodes.length; i++) { const node = this.options.stopNodes[i]; if (typeof node === 'string') { this.stopNodeExpressions.push(new Expression(node)); } else if (node instanceof Expression) { this.stopNodeExpressions.push(node); } } } if (this.options.ignoreAttributes === true || this.options.attributesGroupName) { this.isAttribute = function (/*a*/) { return false; }; } else { this.ignoreAttributesFn = getIgnoreAttributesFn(this.options.ignoreAttributes); this.attrPrefixLen = this.options.attributeNamePrefix.length; this.isAttribute = isAttribute; } this.processTextOrObjNode = processTextOrObjNode; if (this.options.format) { this.indentate = indentate; this.tagEndChar = '>\n'; this.newLine = '\n'; } else { this.indentate = function () { return ''; }; this.tagEndChar = '>'; this.newLine = ''; } } /** * Detect XML version from the ?xml declaration at the root of a plain-object input. * Checks both attributesGroupName and flat attribute forms. * Returns '1.0' if no declaration is found. */ function detectXmlVersionFromObj(jObj, options) { const decl = jObj['?xml']; if (decl && typeof decl === 'object') { // attributesGroupName path e.g. { '$$': { '@_version': '1.1' } } if (options.attributesGroupName && decl[options.attributesGroupName]) { const v = decl[options.attributesGroupName][options.attributeNamePrefix + 'version']; if (v) return v; } // flat attribute path e.g. { '@_version': '1.1' } const v = decl[options.attributeNamePrefix + 'version']; if (v) return v; } return '1.0'; } /** * Resolve a tag or attribute name through sanitizeName if configured. * Validation via xml-naming's qName is performed first; the sanitizeName * callback is invoked only when the name is invalid. If sanitizeName is * false (default), no validation occurs and the name is used as-is. * * @param {string} name - raw name from the JS object * @param {boolean} isAttribute - true when resolving an attribute name * @param {object} options * @param {Matcher} matcher - current matcher state (readonly from callback perspective) * @param {string} xmlVersion - '1.0' or '1.1', forwarded to xml-naming */ function resolveTagName(name, isAttribute, options, matcher, xmlVersion) { if (!options.sanitizeName) return name; if (qName(name, { xmlVersion })) return name; return options.sanitizeName(name, { isAttribute, matcher: matcher.readOnly() }); } Builder.prototype.build = function (jObj) { if (this.options.preserveOrder) { return toXml(jObj, this.options); } else { if (Array.isArray(jObj) && this.options.arrayNodeName && this.options.arrayNodeName.length > 1) { jObj = { [this.options.arrayNodeName]: jObj }; } // Initialize matcher for path tracking const matcher = new Matcher(); const xmlVersion = detectXmlVersionFromObj(jObj, this.options); return this.j2x(jObj, 0, matcher, xmlVersion).val; } }; Builder.prototype.j2x = function (jObj, level, matcher, xmlVersion) { let attrStr = ''; let val = ''; if (this.options.maxNestedTags && matcher.getDepth() >= this.options.maxNestedTags) { throw new Error("Maximum nested tags exceeded"); } // Get jPath based on option: string for backward compatibility, or Matcher for new features const jPath = this.options.jPath ? matcher.toString() : matcher; // Check if current node is a stopNode (will be used for attribute encoding) const isCurrentStopNode = this.checkStopNode(matcher); for (let key in jObj) { if (!Object.prototype.hasOwnProperty.call(jObj, key)) continue; // Resolve the key through sanitizeName before any use. // Special keys (textNodeName, cdataPropName, commentPropName, attributeNamePrefix, // attributesGroupName, "?" PI tags) are exempt — they are builder-internal conventions, // not user-supplied XML names. const isSpecialKey = key === this.options.textNodeName || key === this.options.cdataPropName || key === this.options.commentPropName || (this.options.attributesGroupName && key === this.options.attributesGroupName) || this.isAttribute(key) || key[0] === '?'; const resolvedKey = isSpecialKey ? key : resolveTagName(key, false, this.options, matcher, xmlVersion); if (typeof jObj[key] === 'undefined') { // supress undefined node only if it is not an attribute if (this.isAttribute(key)) { val += ''; } } else if (jObj[key] === null) { // null attribute should be ignored by the attribute list, but should not cause the tag closing if (this.isAttribute(key)) { val += ''; } else if (resolvedKey === this.options.cdataPropName || resolvedKey === this.options.commentPropName) { val += ''; } else if (resolvedKey[0] === '?') { val += this.indentate(level) + '<' + resolvedKey + '?' + this.tagEndChar; } else { val += this.indentate(level) + '<' + resolvedKey + '/' + this.tagEndChar; } } else if (jObj[key] instanceof Date) { val += this.buildTextValNode(jObj[key], resolvedKey, '', level, matcher); } else if (typeof jObj[key] !== 'object') { //premitive type const attr = this.isAttribute(key); if (attr && !this.ignoreAttributesFn(attr, jPath)) { // Resolve the attribute name through sanitizeName const resolvedAttr = resolveTagName(attr, true, this.options, matcher, xmlVersion); attrStr += this.buildAttrPairStr(resolvedAttr, '' + jObj[key], isCurrentStopNode); } else if (!attr) { //tag value if (key === this.options.textNodeName) { let newval = this.options.tagValueProcessor(key, '' + jObj[key]); val += this.replaceEntitiesValue(newval); } else { // Check if this is a stopNode before building matcher.push(resolvedKey); const isStopNode = this.checkStopNode(matcher); matcher.pop(); if (isStopNode) { // Build as raw content without encoding const textValue = '' + jObj[key]; if (textValue === '') { val += this.indentate(level) + '<' + resolvedKey + this.closeTag(resolvedKey) + this.tagEndChar; } else { val += this.indentate(level) + '<' + resolvedKey + '>' + textValue + '' + textValue + '${item}`; } else if (typeof item === 'object' && item !== null) { const nestedContent = this.buildRawContent(item); const nestedAttrs = this.buildAttributesForStopNode(item); if (nestedContent === '') { content += `<${key}${nestedAttrs}/>`; } else { content += `<${key}${nestedAttrs}>${nestedContent}`; } } } } else if (typeof value === 'object' && value !== null) { // Nested object const nestedContent = this.buildRawContent(value); const nestedAttrs = this.buildAttributesForStopNode(value); if (nestedContent === '') { content += `<${key}${nestedAttrs}/>`; } else { content += `<${key}${nestedAttrs}>${nestedContent}`; } } else { // Primitive value content += `<${key}>${value}`; } } return content; }; // Build attribute string for stopNode (no entity encoding) Builder.prototype.buildAttributesForStopNode = function (obj) { if (!obj || typeof obj !== 'object') return ''; let attrStr = ''; // Check for attributesGroupName (when attributes are grouped) if (this.options.attributesGroupName && obj[this.options.attributesGroupName]) { const attrGroup = obj[this.options.attributesGroupName]; for (let attrKey in attrGroup) { if (!Object.prototype.hasOwnProperty.call(attrGroup, attrKey)) continue; const cleanKey = attrKey.startsWith(this.options.attributeNamePrefix) ? attrKey.substring(this.options.attributeNamePrefix.length) : attrKey; const val = attrGroup[attrKey]; if (val === true && this.options.suppressBooleanAttributes) { attrStr += ' ' + cleanKey; } else { attrStr += ' ' + cleanKey + '="' + val + '"'; // No encoding for stopNode } } } else { // Look for individual attributes for (let key in obj) { if (!Object.prototype.hasOwnProperty.call(obj, key)) continue; const attr = this.isAttribute(key); if (attr) { const val = obj[key]; if (val === true && this.options.suppressBooleanAttributes) { attrStr += ' ' + attr; } else { attrStr += ' ' + attr + '="' + val + '"'; // No encoding for stopNode } } } } return attrStr; }; Builder.prototype.buildObjectNode = function (val, key, attrStr, level) { if (val === "") { if (key[0] === "?") return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar; else { return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar; } } else if (key[0] === "?") { // PI/XML-declaration tags never have body content — treat them like empty. return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar; } else { let tagEndExp = '' + val + tagEndExp); } else if (this.options.commentPropName !== false && key === this.options.commentPropName && piClosingChar.length === 0) { return this.indentate(level) + `` + this.newLine; } else { return ( this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar + val + this.indentate(level) + tagEndExp); } } }; Builder.prototype.closeTag = function (key) { let closeTag = ""; if (this.options.unpairedTags.indexOf(key) !== -1) { //unpaired if (!this.options.suppressUnpairedNode) closeTag = "/"; } else if (this.options.suppressEmptyNode) { //empty closeTag = "/"; } else { closeTag = `>` + this.newLine; } else if (this.options.commentPropName !== false && key === this.options.commentPropName) { const safeVal = safeComment(val); return this.indentate(level) + `` + this.newLine; } else if (key[0] === "?") {//PI tag return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar; } else { // Normal processing: apply tagValueProcessor and entity replacement let textValue = this.options.tagValueProcessor(key, val); textValue = this.replaceEntitiesValue(textValue); if (textValue === '') { return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar; } else { return this.indentate(level) + '<' + key + attrStr + '>' + textValue + ' 0 && this.options.processEntities) { for (let i = 0; i < this.options.entities.length; i++) { const entity = this.options.entities[i]; textValue = textValue.replace(entity.regex, entity.val); } } return textValue; }; function indentate(level) { return this.options.indentBy.repeat(level); } function isAttribute(name /*, options*/) { if (name.startsWith(this.options.attributeNamePrefix) && name !== this.options.textNodeName) { return name.substr(this.attrPrefixLen); } else { return false; } } const XMLValidator = { validate: validate }; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Default key used to access the XML attributes. */ const XML_ATTRKEY = "$"; /** * Default key used to access the XML value content. */ const XML_CHARKEY = "_"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function getCommonOptions(options) { return { attributesGroupName: XML_ATTRKEY, textNodeName: options.xmlCharKey ?? XML_CHARKEY, ignoreAttributes: false, suppressBooleanAttributes: false, }; } function getSerializerOptions(options = {}) { return { ...getCommonOptions(options), attributeNamePrefix: "@_", format: true, suppressEmptyNode: true, indentBy: "", rootNodeName: options.rootName ?? "root", cdataPropName: options.cdataPropName ?? "__cdata", }; } function getParserOptions(options = {}) { return { ...getCommonOptions(options), parseAttributeValue: false, parseTagValue: false, attributeNamePrefix: "", stopNodes: options.stopNodes, processEntities: true, trimValues: false, }; } /** * Converts given JSON object to XML string * @param obj - JSON object to be converted into XML string * @param opts - Options that govern the XML building of given JSON object * `rootName` indicates the name of the root element in the resulting XML */ function stringifyXML(obj, opts = {}) { const parserOptions = getSerializerOptions(opts); const j2x = new Builder(parserOptions); const node = { [parserOptions.rootNodeName]: obj }; const xmlData = j2x.build(node); return `${xmlData}`.replace(/\n/g, ""); } /** * Converts given XML string into JSON * @param str - String containing the XML content to be parsed into JSON * @param opts - Options that govern the parsing of given xml string * `includeRoot` indicates whether the root element is to be included or not in the output */ async function parseXML(str, opts = {}) { if (!str) { throw new Error("Document is empty"); } const validation = XMLValidator.validate(str); if (validation !== true) { throw validation; } const parser = new XMLParser(getParserOptions(opts)); const parsedXml = parser.parse(str); // Remove the node. // This is a change in behavior on fxp v4. Issue #424 if (parsedXml["?xml"]) { delete parsedXml["?xml"]; } if (!opts.includeRoot) { for (const key of Object.keys(parsedXml)) { const value = parsedXml[key]; return typeof value === "object" ? { ...value } : value; } } return parsedXml; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The `@azure/logger` configuration for this package. */ const logger$1 = createClientLogger("storage-blob"); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * This class generates a readable stream from the data in an array of buffers. */ class BuffersStream extends Readable$1 { buffers; byteLength; /** * The offset of data to be read in the current buffer. */ byteOffsetInCurrentBuffer; /** * The index of buffer to be read in the array of buffers. */ bufferIndex; /** * The total length of data already read. */ pushedBytesLength; /** * Creates an instance of BuffersStream that will emit the data * contained in the array of buffers. * * @param buffers - Array of buffers containing the data * @param byteLength - The total length of data contained in the buffers */ constructor(buffers, byteLength, options) { super(options); this.buffers = buffers; this.byteLength = byteLength; this.byteOffsetInCurrentBuffer = 0; this.bufferIndex = 0; this.pushedBytesLength = 0; // check byteLength is no larger than buffers[] total length let buffersLength = 0; for (const buf of this.buffers) { buffersLength += buf.byteLength; } if (buffersLength < this.byteLength) { throw new Error("Data size shouldn't be larger than the total length of buffers."); } } /** * Internal _read() that will be called when the stream wants to pull more data in. * * @param size - Optional. The size of data to be read */ _read(size) { if (this.pushedBytesLength >= this.byteLength) { this.push(null); } if (!size) { size = this.readableHighWaterMark; } const outBuffers = []; let i = 0; while (i < size && this.pushedBytesLength < this.byteLength) { // The last buffer may be longer than the data it contains. const remainingDataInAllBuffers = this.byteLength - this.pushedBytesLength; const remainingCapacityInThisBuffer = this.buffers[this.bufferIndex].byteLength - this.byteOffsetInCurrentBuffer; const remaining = Math.min(remainingCapacityInThisBuffer, remainingDataInAllBuffers); if (remaining > size - i) { // chunkSize = size - i const end = this.byteOffsetInCurrentBuffer + size - i; outBuffers.push(this.buffers[this.bufferIndex].slice(this.byteOffsetInCurrentBuffer, end)); this.pushedBytesLength += size - i; this.byteOffsetInCurrentBuffer = end; i = size; break; } else { // chunkSize = remaining const end = this.byteOffsetInCurrentBuffer + remaining; outBuffers.push(this.buffers[this.bufferIndex].slice(this.byteOffsetInCurrentBuffer, end)); if (remaining === remainingCapacityInThisBuffer) { // this.buffers[this.bufferIndex] used up, shift to next one this.byteOffsetInCurrentBuffer = 0; this.bufferIndex++; } else { this.byteOffsetInCurrentBuffer = end; } this.pushedBytesLength += remaining; i += remaining; } } if (outBuffers.length > 1) { this.push(Buffer.concat(outBuffers)); } else if (outBuffers.length === 1) { this.push(outBuffers[0]); } } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * maxBufferLength is max size of each buffer in the pooled buffers. */ const maxBufferLength = require$$0$4.constants.MAX_LENGTH; /** * This class provides a buffer container which conceptually has no hard size limit. * It accepts a capacity, an array of input buffers and the total length of input data. * It will allocate an internal "buffer" of the capacity and fill the data in the input buffers * into the internal "buffer" serially with respect to the total length. * Then by calling PooledBuffer.getReadableStream(), you can get a readable stream * assembled from all the data in the internal "buffer". */ class PooledBuffer { /** * Internal buffers used to keep the data. * Each buffer has a length of the maxBufferLength except last one. */ buffers = []; /** * The total size of internal buffers. */ capacity; /** * The total size of data contained in internal buffers. */ _size; /** * The size of the data contained in the pooled buffers. */ get size() { return this._size; } constructor(capacity, buffers, totalLength) { this.capacity = capacity; this._size = 0; // allocate const bufferNum = Math.ceil(capacity / maxBufferLength); for (let i = 0; i < bufferNum; i++) { let len = i === bufferNum - 1 ? capacity % maxBufferLength : maxBufferLength; if (len === 0) { len = maxBufferLength; } this.buffers.push(Buffer.allocUnsafe(len)); } if (buffers) { this.fill(buffers, totalLength); } } /** * Fill the internal buffers with data in the input buffers serially * with respect to the total length and the total capacity of the internal buffers. * Data copied will be shift out of the input buffers. * * @param buffers - Input buffers containing the data to be filled in the pooled buffer * @param totalLength - Total length of the data to be filled in. * */ fill(buffers, totalLength) { this._size = Math.min(this.capacity, totalLength); let i = 0, j = 0, targetOffset = 0, sourceOffset = 0, totalCopiedNum = 0; while (totalCopiedNum < this._size) { const source = buffers[i]; const target = this.buffers[j]; const copiedNum = source.copy(target, targetOffset, sourceOffset); totalCopiedNum += copiedNum; sourceOffset += copiedNum; targetOffset += copiedNum; if (sourceOffset === source.length) { i++; sourceOffset = 0; } if (targetOffset === target.length) { j++; targetOffset = 0; } } // clear copied from source buffers buffers.splice(0, i); if (buffers.length > 0) { buffers[0] = buffers[0].slice(sourceOffset); } } /** * Get the readable stream assembled from all the data in the internal buffers. * */ getReadableStream() { return new BuffersStream(this.buffers, this.size); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * This class accepts a Node.js Readable stream as input, and keeps reading data * from the stream into the internal buffer structure, until it reaches maxBuffers. * Every available buffer will try to trigger outgoingHandler. * * The internal buffer structure includes an incoming buffer array, and a outgoing * buffer array. The incoming buffer array includes the "empty" buffers can be filled * with new incoming data. The outgoing array includes the filled buffers to be * handled by outgoingHandler. Every above buffer size is defined by parameter bufferSize. * * NUM_OF_ALL_BUFFERS = BUFFERS_IN_INCOMING + BUFFERS_IN_OUTGOING + BUFFERS_UNDER_HANDLING * * NUM_OF_ALL_BUFFERS lesser than or equal to maxBuffers * * PERFORMANCE IMPROVEMENT TIPS: * 1. Input stream highWaterMark is better to set a same value with bufferSize * parameter, which will avoid Buffer.concat() operations. * 2. concurrency should set a smaller value than maxBuffers, which is helpful to * reduce the possibility when a outgoing handler waits for the stream data. * in this situation, outgoing handlers are blocked. * Outgoing queue shouldn't be empty. */ class BufferScheduler { /** * Size of buffers in incoming and outgoing queues. This class will try to align * data read from Readable stream into buffer chunks with bufferSize defined. */ bufferSize; /** * How many buffers can be created or maintained. */ maxBuffers; /** * A Node.js Readable stream. */ readable; /** * OutgoingHandler is an async function triggered by BufferScheduler when there * are available buffers in outgoing array. */ outgoingHandler; /** * An internal event emitter. */ emitter = new EventEmitter(); /** * Concurrency of executing outgoingHandlers. (0 lesser than concurrency lesser than or equal to maxBuffers) */ concurrency; /** * An internal offset marker to track data offset in bytes of next outgoingHandler. */ offset = 0; /** * An internal marker to track whether stream is end. */ isStreamEnd = false; /** * An internal marker to track whether stream or outgoingHandler returns error. */ isError = false; /** * How many handlers are executing. */ executingOutgoingHandlers = 0; /** * Encoding of the input Readable stream which has string data type instead of Buffer. */ encoding; /** * How many buffers have been allocated. */ numBuffers = 0; /** * Because this class doesn't know how much data every time stream pops, which * is defined by highWaterMarker of the stream. So BufferScheduler will cache * data received from the stream, when data in unresolvedDataArray exceeds the * blockSize defined, it will try to concat a blockSize of buffer, fill into available * buffers from incoming and push to outgoing array. */ unresolvedDataArray = []; /** * How much data consisted in unresolvedDataArray. */ unresolvedLength = 0; /** * The array includes all the available buffers can be used to fill data from stream. */ incoming = []; /** * The array (queue) includes all the buffers filled from stream data. */ outgoing = []; /** * Creates an instance of BufferScheduler. * * @param readable - A Node.js Readable stream * @param bufferSize - Buffer size of every maintained buffer * @param maxBuffers - How many buffers can be allocated * @param outgoingHandler - An async function scheduled to be * triggered when a buffer fully filled * with stream data * @param concurrency - Concurrency of executing outgoingHandlers (>0) * @param encoding - [Optional] Encoding of Readable stream when it's a string stream */ constructor(readable, bufferSize, maxBuffers, outgoingHandler, concurrency, encoding) { if (bufferSize <= 0) { throw new RangeError(`bufferSize must be larger than 0, current is ${bufferSize}`); } if (maxBuffers <= 0) { throw new RangeError(`maxBuffers must be larger than 0, current is ${maxBuffers}`); } if (concurrency <= 0) { throw new RangeError(`concurrency must be larger than 0, current is ${concurrency}`); } this.bufferSize = bufferSize; this.maxBuffers = maxBuffers; this.readable = readable; this.outgoingHandler = outgoingHandler; this.concurrency = concurrency; this.encoding = encoding; } /** * Start the scheduler, will return error when stream of any of the outgoingHandlers * returns error. * */ async do() { return new Promise((resolve, reject) => { this.readable.on("data", (data) => { data = typeof data === "string" ? Buffer.from(data, this.encoding) : data; this.appendUnresolvedData(data); if (!this.resolveData()) { this.readable.pause(); } }); this.readable.on("error", (err) => { this.emitter.emit("error", err); }); this.readable.on("end", () => { this.isStreamEnd = true; this.emitter.emit("checkEnd"); }); this.emitter.on("error", (err) => { this.isError = true; this.readable.pause(); reject(err); }); this.emitter.on("checkEnd", () => { if (this.outgoing.length > 0) { this.triggerOutgoingHandlers(); return; } if (this.isStreamEnd && this.executingOutgoingHandlers === 0) { if (this.unresolvedLength > 0 && this.unresolvedLength < this.bufferSize) { const buffer = this.shiftBufferFromUnresolvedDataArray(); this.outgoingHandler(() => buffer.getReadableStream(), buffer.size, this.offset) .then(resolve) .catch(reject); } else if (this.unresolvedLength >= this.bufferSize) { return; } else { resolve(); } } }); }); } /** * Insert a new data into unresolved array. * * @param data - */ appendUnresolvedData(data) { this.unresolvedDataArray.push(data); this.unresolvedLength += data.length; } /** * Try to shift a buffer with size in blockSize. The buffer returned may be less * than blockSize when data in unresolvedDataArray is less than bufferSize. * */ shiftBufferFromUnresolvedDataArray(buffer) { if (!buffer) { buffer = new PooledBuffer(this.bufferSize, this.unresolvedDataArray, this.unresolvedLength); } else { buffer.fill(this.unresolvedDataArray, this.unresolvedLength); } this.unresolvedLength -= buffer.size; return buffer; } /** * Resolve data in unresolvedDataArray. For every buffer with size in blockSize * shifted, it will try to get (or allocate a buffer) from incoming, and fill it, * then push it into outgoing to be handled by outgoing handler. * * Return false when available buffers in incoming are not enough, else true. * * @returns Return false when buffers in incoming are not enough, else true. */ resolveData() { while (this.unresolvedLength >= this.bufferSize) { let buffer; if (this.incoming.length > 0) { buffer = this.incoming.shift(); this.shiftBufferFromUnresolvedDataArray(buffer); } else { if (this.numBuffers < this.maxBuffers) { buffer = this.shiftBufferFromUnresolvedDataArray(); this.numBuffers++; } else { // No available buffer, wait for buffer returned return false; } } this.outgoing.push(buffer); this.triggerOutgoingHandlers(); } return true; } /** * Try to trigger a outgoing handler for every buffer in outgoing. Stop when * concurrency reaches. */ async triggerOutgoingHandlers() { let buffer; do { if (this.executingOutgoingHandlers >= this.concurrency) { return; } buffer = this.outgoing.shift(); if (buffer) { this.triggerOutgoingHandler(buffer); } } while (buffer); } /** * Trigger a outgoing handler for a buffer shifted from outgoing. * * @param buffer - */ async triggerOutgoingHandler(buffer) { const bufferLength = buffer.size; this.executingOutgoingHandlers++; this.offset += bufferLength; try { await this.outgoingHandler(() => buffer.getReadableStream(), bufferLength, this.offset - bufferLength); } catch (err) { this.emitter.emit("error", err); return; } this.executingOutgoingHandlers--; this.reuseBuffer(buffer); this.emitter.emit("checkEnd"); } /** * Return buffer used by outgoing handler into incoming. * * @param buffer - */ reuseBuffer(buffer) { this.incoming.push(buffer); if (!this.isError && this.resolveData() && !this.isStreamEnd) { this.readable.resume(); } } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. /** * This error is thrown when an asynchronous operation has been aborted. * Check for this error by testing the `name` that the name property of the * error matches `"AbortError"`. * * @example * ```ts * const controller = new AbortController(); * controller.abort(); * try { * doAsyncWork(controller.signal) * } catch (e) { * if (e.name === 'AbortError') { * // handle abort error here. * } * } * ``` */ let AbortError$1 = class AbortError extends Error { constructor(message) { super(message); this.name = "AbortError"; } }; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const __isNode__ = typeof process === "object" && typeof process.versions === "object" && typeof process.versions.node === "string"; let require$1; let __filename$1; let __dirname$1; if (__isNode__) { require$1 = createRequire(import.meta.url); __filename$1 = fileURLToPath(import.meta.url); __dirname$1 = dirname$1(__filename$1); } // ESM-COMPAT-END var NativeCRC64 = (() => { var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; if (typeof __filename$1 !== 'undefined') _scriptDir = _scriptDir || __filename$1; return ( function(NativeCRC64) { NativeCRC64 = NativeCRC64 || {}; // The Module object: Our interface to the outside world. We import // and export values on it. There are various ways Module can be used: // 1. Not defined. We create it here // 2. A function parameter, function(Module) { ..generated code.. } // 3. pre-run appended it, var Module = {}; ..generated code.. // 4. External script tag defines var Module. // We need to check if Module already exists (e.g. case 3 above). // Substitution will be replaced with actual code on later stage of the build, // this way Closure Compiler will not mangle it (e.g. case 4. above). // Note that if you want to run closure, and also to use Module // after the generated code, you will need to define var Module = {}; // before the code. Then that object will be used in the code, and you // can continue to use Module afterwards as well. var Module = typeof NativeCRC64 != 'undefined' ? NativeCRC64 : {}; // See https://caniuse.com/mdn-javascript_builtins_object_assign // See https://caniuse.com/mdn-javascript_builtins_bigint64array // Set up the promise that indicates the Module is initialized var readyPromiseResolve, readyPromiseReject; Module['ready'] = new Promise(function(resolve, reject) { readyPromiseResolve = resolve; readyPromiseReject = reject; }); ["_malloc","_free","_emscripten_bind_VoidPtr___destroy___0","_emscripten_bind_Crc64Hash_Crc64Hash_0","_emscripten_bind_Crc64Hash_OnAppend_2","_emscripten_bind_Crc64Hash_OnFinal_3","_emscripten_bind_Crc64Hash___destroy___0","_fflush","onRuntimeInitialized"].forEach((prop) => { if (!Object.getOwnPropertyDescriptor(Module['ready'], prop)) { Object.defineProperty(Module['ready'], prop, { get: () => abort('You are getting ' + prop + ' on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js'), set: () => abort('You are setting ' + prop + ' on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js'), }); } }); // --pre-jses are emitted after the Module integration code, so that they can // refer to Module (if they choose; they can also define Module) // Sometimes an existing Module object exists with properties // meant to overwrite the default module functionality. Here // we collect those properties and reapply _after_ we configure // the current environment's defaults to avoid having to be so // defensive during initialization. var moduleOverrides = Object.assign({}, Module); // Determine the runtime environment we are in. You can customize this by // setting the ENVIRONMENT setting at compile time (see settings.js). // Attempt to auto-detect the environment var ENVIRONMENT_IS_WEB = typeof window == 'object'; var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'; // N.b. Electron.js environment is simultaneously a NODE-environment, but // also a web environment. var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string'; var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; if (Module['ENVIRONMENT']) { throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node)'); } // `/` should be present at the end if `scriptDirectory` is not empty var scriptDirectory = ''; function locateFile(path) { if (Module['locateFile']) { return Module['locateFile'](path, scriptDirectory); } return scriptDirectory + path; } if (ENVIRONMENT_IS_NODE) { if (typeof process == 'undefined' || !process.release || process.release.name !== 'node') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); // `require()` is no-op in an ESM module, use `createRequire()` to construct // the require()` function. This is only necessary for multi-environment // builds, `-sENVIRONMENT=node` emits a static import declaration instead. // TODO: Swap all `require()`'s with `import()`'s? // These modules will usually be used on Node.js. Load them eagerly to avoid // the complexity of lazy-loading. require$1('fs'); var nodePath = require$1('path'); if (ENVIRONMENT_IS_WORKER) { scriptDirectory = nodePath.dirname(scriptDirectory) + '/'; } else { scriptDirectory = __dirname$1 + '/'; } // end include: node_shell_read.js if (process['argv'].length > 1) { process['argv'][1].replace(/\\/g, '/'); } process['argv'].slice(2); // MODULARIZE will export the module in the proper place outside, we don't need to export here process['on']('uncaughtException', function(ex) { // suppress ExitStatus exceptions from showing an error if (!(ex instanceof ExitStatus)) { throw ex; } }); // Without this older versions of node (< v15) will log unhandled rejections // but return 0, which is not normally the desired behaviour. This is // not be needed with node v15 and about because it is now the default // behaviour: // See https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode process['on']('unhandledRejection', function(reason) { throw reason; }); Module['inspect'] = function () { return '[Emscripten Module object]'; }; } else if (ENVIRONMENT_IS_SHELL) { if ((typeof process == 'object' && typeof require$1 === 'function') || typeof window == 'object' || typeof importScripts == 'function') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); if (typeof scriptArgs != 'undefined') { scriptArgs; } if (typeof print != 'undefined') { // Prefer to use print/printErr where they exist, as they usually work better. if (typeof console == 'undefined') console = /** @type{!Console} */({}); console.log = /** @type{!function(this:Console, ...*): undefined} */ (print); console.warn = console.error = /** @type{!function(this:Console, ...*): undefined} */ (typeof printErr != 'undefined' ? printErr : print); } } else // Note that this includes Node.js workers when relevant (pthreads is enabled). // Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and // ENVIRONMENT_IS_NODE. if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { if (ENVIRONMENT_IS_WORKER) { // Check worker, not web, since window could be polyfilled scriptDirectory = self.location.href; } else if (typeof document != 'undefined' && document.currentScript) { // web scriptDirectory = document.currentScript.src; } // When MODULARIZE, this JS may be executed later, after document.currentScript // is gone, so we saved it, and we use it here instead of any other info. if (_scriptDir) { scriptDirectory = _scriptDir; } // blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them. // otherwise, slice off the final part of the url to find the script directory. // if scriptDirectory does not contain a slash, lastIndexOf will return -1, // and scriptDirectory will correctly be replaced with an empty string. // If scriptDirectory contains a query (starting with ?) or a fragment (starting with #), // they are removed because they could contain a slash. if (scriptDirectory.indexOf('blob:') !== 0) { scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf('/')+1); } else { scriptDirectory = ''; } if (!(typeof window == 'object' || typeof importScripts == 'function')) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); } else { throw new Error('environment detection error'); } var out = Module['print'] || console.log.bind(console); var err = Module['printErr'] || console.warn.bind(console); // Merge back in the overrides Object.assign(Module, moduleOverrides); // Free the object hierarchy contained in the overrides, this lets the GC // reclaim data used e.g. in memoryInitializerRequest, which is a large typed array. moduleOverrides = null; checkIncomingModuleAPI(); // Emit code to handle expected values on the Module object. This applies Module.x // to the proper local x. This has two benefits: first, we only emit it if it is // expected to arrive, and second, by using a local everywhere else that can be // minified. if (Module['arguments']) Module['arguments'];legacyModuleProp('arguments', 'arguments_'); if (Module['thisProgram']) Module['thisProgram'];legacyModuleProp('thisProgram', 'thisProgram'); if (Module['quit']) Module['quit'];legacyModuleProp('quit', 'quit_'); // perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message // Assertions on removed incoming Module JS APIs. assert(typeof Module['memoryInitializerPrefixURL'] == 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead'); assert(typeof Module['pthreadMainPrefixURL'] == 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead'); assert(typeof Module['cdInitializerPrefixURL'] == 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead'); assert(typeof Module['filePackagePrefixURL'] == 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead'); assert(typeof Module['read'] == 'undefined', 'Module.read option was removed (modify read_ in JS)'); assert(typeof Module['readAsync'] == 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)'); assert(typeof Module['readBinary'] == 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)'); assert(typeof Module['setWindowTitle'] == 'undefined', 'Module.setWindowTitle option was removed (modify setWindowTitle in JS)'); assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY'); legacyModuleProp('read', 'read_'); legacyModuleProp('readAsync', 'readAsync'); legacyModuleProp('readBinary', 'readBinary'); legacyModuleProp('setWindowTitle', 'setWindowTitle'); assert(!ENVIRONMENT_IS_SHELL, "shell environment detected but not enabled at build time. Add 'shell' to `-sENVIRONMENT` to enable."); // include: runtime_debug.js function legacyModuleProp(prop, newName) { if (!Object.getOwnPropertyDescriptor(Module, prop)) { Object.defineProperty(Module, prop, { configurable: true, get: function() { abort('Module.' + prop + ' has been replaced with plain ' + newName + ' (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)'); } }); } } function ignoredModuleProp(prop) { if (Object.getOwnPropertyDescriptor(Module, prop)) { abort('`Module.' + prop + '` was supplied but `' + prop + '` not included in INCOMING_MODULE_JS_API'); } } // forcing the filesystem exports a few things by default function isExportedByForceFilesystem(name) { return name === 'FS_createPath' || name === 'FS_createDataFile' || name === 'FS_createPreloadedFile' || name === 'FS_unlink' || name === 'addRunDependency' || // The old FS has some functionality that WasmFS lacks. name === 'FS_createLazyFile' || name === 'FS_createDevice' || name === 'removeRunDependency'; } function missingLibrarySymbol(sym) { if (typeof globalThis !== 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) { Object.defineProperty(globalThis, sym, { configurable: true, get: function() { // Can't `abort()` here because it would break code that does runtime // checks. e.g. `if (typeof SDL === 'undefined')`. var msg = '`' + sym + '` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line'; // DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in // library.js, which means $name for a JS name with no prefix, or name // for a JS name like _name. var librarySymbol = sym; if (!librarySymbol.startsWith('_')) { librarySymbol = '$' + sym; } msg += " (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=" + librarySymbol + ")"; if (isExportedByForceFilesystem(sym)) { msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; } warnOnce(msg); return undefined; } }); } } function unexportedRuntimeSymbol(sym) { if (!Object.getOwnPropertyDescriptor(Module, sym)) { Object.defineProperty(Module, sym, { configurable: true, get: function() { var msg = "'" + sym + "' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)"; if (isExportedByForceFilesystem(sym)) { msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; } abort(msg); } }); } } if (Module['wasmBinary']) Module['wasmBinary'];legacyModuleProp('wasmBinary', 'wasmBinary'); Module['noExitRuntime'] || true;legacyModuleProp('noExitRuntime', 'noExitRuntime'); if (typeof WebAssembly != 'object') { abort('no native wasm support detected'); } // Wasm globals var wasmMemory; //======================================== // Runtime essentials //======================================== // whether we are quitting the application. no code should run after this. // set in exit() and abort() var ABORT = false; /** @type {function(*, string=)} */ function assert(condition, text) { if (!condition) { abort('Assertion failed' + (text ? ': ' + text : '')); } } // We used to include malloc/free by default in the past. Show a helpful error in // builds with assertions. // include: runtime_strings.js // runtime_strings.js: String related runtime functions that are part of both // MINIMAL_RUNTIME and regular runtime. var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined; /** * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given * array that contains uint8 values, returns a copy of that string as a * Javascript String object. * heapOrArray is either a regular array, or a JavaScript typed array view. * @param {number} idx * @param {number=} maxBytesToRead * @return {string} */ function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) { var endIdx = idx + maxBytesToRead; var endPtr = idx; // TextDecoder needs to know the byte length in advance, it doesn't stop on // null terminator by itself. Also, use the length info to avoid running tiny // strings through TextDecoder, since .subarray() allocates garbage. // (As a tiny code save trick, compare endPtr against endIdx using a negation, // so that undefined means Infinity) while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); } var str = ''; // If building with TextDecoder, we have already computed the string length // above, so test loop end condition against that while (idx < endPtr) { // For UTF8 byte structure, see: // http://en.wikipedia.org/wiki/UTF-8#Description // https://www.ietf.org/rfc/rfc2279.txt // https://tools.ietf.org/html/rfc3629 var u0 = heapOrArray[idx++]; if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; } var u1 = heapOrArray[idx++] & 63; if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; } var u2 = heapOrArray[idx++] & 63; if ((u0 & 0xF0) == 0xE0) { u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; } else { if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte ' + ptrToString(u0) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!'); u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63); } if (u0 < 0x10000) { str += String.fromCharCode(u0); } else { var ch = u0 - 0x10000; str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); } } return str; } // end include: runtime_strings.js // Memory management var /** @type {!ArrayBuffer} */ buffer, /** @type {!Uint8Array} */ HEAPU8, /** @type {!Uint32Array} */ HEAPU32; function updateGlobalBufferAndViews(buf) { buffer = buf; Module['HEAP8'] = new Int8Array(buf); Module['HEAP16'] = new Int16Array(buf); Module['HEAP32'] = new Int32Array(buf); Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf); Module['HEAPU16'] = new Uint16Array(buf); Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf); Module['HEAPF32'] = new Float32Array(buf); Module['HEAPF64'] = new Float64Array(buf); } var STACK_SIZE = 5242880; if (Module['STACK_SIZE']) assert(STACK_SIZE === Module['STACK_SIZE'], 'the stack size can no longer be determined at runtime'); var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216;legacyModuleProp('INITIAL_MEMORY', 'INITIAL_MEMORY'); assert(INITIAL_MEMORY >= STACK_SIZE, 'INITIAL_MEMORY should be larger than STACK_SIZE, was ' + INITIAL_MEMORY + '! (STACK_SIZE=' + STACK_SIZE + ')'); // check for full engine support (use string 'subarray' to avoid closure compiler confusion) assert(typeof Int32Array != 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray != undefined && Int32Array.prototype.set != undefined, 'JS engine does not provide full typed array support'); // If memory is defined in wasm, the user can't provide it. assert(!Module['wasmMemory'], 'Use of `wasmMemory` detected. Use -sIMPORTED_MEMORY to define wasmMemory externally'); assert(INITIAL_MEMORY == 16777216, 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically'); // include: runtime_init_table.js // In regular non-RELOCATABLE mode the table is exported // from the wasm module and this will be assigned once // the exports are available. var wasmTable; // end include: runtime_init_table.js // include: runtime_stack_check.js // Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode. function writeStackCookie() { var max = _emscripten_stack_get_end(); assert((max & 3) == 0); // If the stack ends at address zero we write our cookies 4 bytes into the // stack. This prevents interference with the (separate) address-zero check // below. if (max == 0) { max += 4; } // The stack grow downwards towards _emscripten_stack_get_end. // We write cookies to the final two words in the stack and detect if they are // ever overwritten. HEAPU32[((max)>>2)] = 0x2135467; HEAPU32[(((max)+(4))>>2)] = 0x89BACDFE; // Also test the global address 0 for integrity. HEAPU32[0] = 0x63736d65; /* 'emsc' */ } function checkStackCookie() { if (ABORT) return; var max = _emscripten_stack_get_end(); // See writeStackCookie(). if (max == 0) { max += 4; } var cookie1 = HEAPU32[((max)>>2)]; var cookie2 = HEAPU32[(((max)+(4))>>2)]; if (cookie1 != 0x2135467 || cookie2 != 0x89BACDFE) { abort('Stack overflow! Stack cookie has been overwritten at ' + ptrToString(max) + ', expected hex dwords 0x89BACDFE and 0x2135467, but received ' + ptrToString(cookie2) + ' ' + ptrToString(cookie1)); } // Also test the global address 0 for integrity. if (HEAPU32[0] !== 0x63736d65 /* 'emsc' */) { abort('Runtime error: The application has corrupted its heap memory area (address zero)!'); } } // end include: runtime_stack_check.js // include: runtime_assertions.js // Endianness check (function() { var h16 = new Int16Array(1); var h8 = new Int8Array(h16.buffer); h16[0] = 0x6373; if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian! (Run with -sSUPPORT_BIG_ENDIAN to bypass)'; })(); // end include: runtime_assertions.js var __ATPRERUN__ = []; // functions called before the runtime is initialized var __ATINIT__ = []; // functions called during startup var __ATPOSTRUN__ = []; // functions called after the main() is called var runtimeInitialized = false; function preRun() { if (Module['preRun']) { if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; while (Module['preRun'].length) { addOnPreRun(Module['preRun'].shift()); } } callRuntimeCallbacks(__ATPRERUN__); } function initRuntime() { assert(!runtimeInitialized); runtimeInitialized = true; checkStackCookie(); callRuntimeCallbacks(__ATINIT__); } function postRun() { checkStackCookie(); if (Module['postRun']) { if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']]; while (Module['postRun'].length) { addOnPostRun(Module['postRun'].shift()); } } callRuntimeCallbacks(__ATPOSTRUN__); } function addOnPreRun(cb) { __ATPRERUN__.unshift(cb); } function addOnInit(cb) { __ATINIT__.unshift(cb); } function addOnPostRun(cb) { __ATPOSTRUN__.unshift(cb); } // include: runtime_math.js // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc assert(Math.imul, 'This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); assert(Math.fround, 'This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); assert(Math.clz32, 'This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); assert(Math.trunc, 'This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); // end include: runtime_math.js // A counter of dependencies for calling run(). If we need to // do asynchronous work before running, increment this and // decrement it. Incrementing must happen in a place like // Module.preRun (used by emcc to add file preloading). // Note that you can add dependencies in preRun, even though // it happens right before run - run will be postponed until // the dependencies are met. var runDependencies = 0; var runDependencyWatcher = null; var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled var runDependencyTracking = {}; function addRunDependency(id) { runDependencies++; if (Module['monitorRunDependencies']) { Module['monitorRunDependencies'](runDependencies); } { assert(!runDependencyTracking[id]); runDependencyTracking[id] = 1; if (runDependencyWatcher === null && typeof setInterval != 'undefined') { // Check for missing dependencies every few seconds runDependencyWatcher = setInterval(function() { if (ABORT) { clearInterval(runDependencyWatcher); runDependencyWatcher = null; return; } var shown = false; for (var dep in runDependencyTracking) { if (!shown) { shown = true; err('still waiting on run dependencies:'); } err('dependency: ' + dep); } if (shown) { err('(end of list)'); } }, 10000); } } } function removeRunDependency(id) { runDependencies--; if (Module['monitorRunDependencies']) { Module['monitorRunDependencies'](runDependencies); } { assert(runDependencyTracking[id]); delete runDependencyTracking[id]; } if (runDependencies == 0) { if (runDependencyWatcher !== null) { clearInterval(runDependencyWatcher); runDependencyWatcher = null; } if (dependenciesFulfilled) { var callback = dependenciesFulfilled; dependenciesFulfilled = null; callback(); // can add another dependenciesFulfilled } } } /** @param {string|number=} what */ function abort(what) { if (Module['onAbort']) { Module['onAbort'](what); } what = 'Aborted(' + what + ')'; // TODO(sbc): Should we remove printing and leave it up to whoever // catches the exception? err(what); ABORT = true; // Use a wasm runtime error, because a JS error might be seen as a foreign // exception, which means we'd run destructors on it. We need the error to // simply make the program stop. // FIXME This approach does not work in Wasm EH because it currently does not assume // all RuntimeErrors are from traps; it decides whether a RuntimeError is from // a trap or not based on a hidden field within the object. So at the moment // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that // allows this in the wasm spec. // Suppress closure compiler warning here. Closure compiler's builtin extern // defintion for WebAssembly.RuntimeError claims it takes no arguments even // though it can. // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed. /** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what); readyPromiseReject(e); // Throw the error whether or not MODULARIZE is set because abort is used // in code paths apart from instantiation where an exception is expected // to be thrown when abort is called. throw e; } // {{MEM_INITIALIZER}} // include: memoryprofiler.js // end include: memoryprofiler.js // show errors on likely calls to FS when it was not included var FS = { error: function() { abort('Filesystem support (FS) was not included. The problem is that you are using files from JS, but files were not used from C/C++, so filesystem support was not auto-included. You can force-include filesystem support with -sFORCE_FILESYSTEM'); }, init: function() { FS.error(); }, createDataFile: function() { FS.error(); }, createPreloadedFile: function() { FS.error(); }, createLazyFile: function() { FS.error(); }, open: function() { FS.error(); }, mkdev: function() { FS.error(); }, registerDevice: function() { FS.error(); }, analyzePath: function() { FS.error(); }, loadFilesFromDB: function() { FS.error(); }, ErrnoError: function ErrnoError() { FS.error(); }, }; Module['FS_createDataFile'] = FS.createDataFile; Module['FS_createPreloadedFile'] = FS.createPreloadedFile; // include: URIUtils.js // Prefix of data URIs emitted by SINGLE_FILE and related options. var dataURIPrefix = 'data:application/octet-stream;base64,'; // Indicates whether filename is a base64 data URI. function isDataURI(filename) { // Prefix of data URIs emitted by SINGLE_FILE and related options. return filename.startsWith(dataURIPrefix); } // Indicates whether filename is delivered via file protocol (as opposed to http/https) function isFileURI(filename) { return filename.startsWith('file://'); } // end include: URIUtils.js /** @param {boolean=} fixedasm */ function createExportWrapper(name, fixedasm) { return function() { var displayName = name; var asm = fixedasm; { asm = Module['asm']; } assert(runtimeInitialized, 'native function `' + displayName + '` called before runtime initialization'); if (!asm[name]) { assert(asm[name], 'exported native function `' + displayName + '` not found'); } return asm[name].apply(null, arguments); }; } var wasmBinaryFile; wasmBinaryFile = 'crc64.wasm'; if (!isDataURI(wasmBinaryFile)) { wasmBinaryFile = locateFile(wasmBinaryFile); } var binaryInString = ["AGFzbQEAAAABzYCAgAAMYAF/AX9gAAF/YAF/AGAAAGADf35/AX5gA39/fwBgBH9/f38AYAN/f38Bf2AFf39", "/f38Bf2AEf39/fwF/YAR/f35/AX5gBH9+f38BfwKPgYCAAAUDZW52BWFib3J0AAMDZW52FmVtc2NyaXB0ZW", "5fcmVzaXplX2hlYXAAABZ3YXNpX3NuYXBzaG90X3ByZXZpZXcxCGZkX2Nsb3NlAAAWd2FzaV9zbmFwc2hvd", "F9wcmV2aWV3MQhmZF93cml0ZQAJFndhc2lfc25hcHNob3RfcHJldmlldzEHZmRfc2VlawAIA62AgIAALAMF", "BgIBAAUGAgEBAAACAAIAAAAHBAQCAgEDAAIAAQIBAQIAAQMBAQEACggLBIWAgIAAAXABBAQFh4CAgAABAYA", "CgIACBsiAgIAACn8BQYCAwAILfwFBAAt/AUEAC38BQQALfwBBnJHBAgt/AEGwkcECC38AQZyRwQILfwBBsJ", "HBAgt/AEGwkcECC38AQZKSwQILB/qEgIAAGwZtZW1vcnkCABFfX3dhc21fY2FsbF9jdG9ycwAFJWVtc2Nya", "XB0ZW5fYmluZF9Wb2lkUHRyX19fZGVzdHJveV9fXzAACCVlbXNjcmlwdGVuX2JpbmRfQ3JjNjRIYXNoX0Ny", "YzY0SGFzaF8wAAkkZW1zY3JpcHRlbl9iaW5kX0NyYzY0SGFzaF9PbkFwcGVuZF8yAAsjZW1zY3JpcHRlbl9", "iaW5kX0NyYzY0SGFzaF9PbkZpbmFsXzMADCdlbXNjcmlwdGVuX2JpbmRfQ3JjNjRIYXNoX19fZGVzdHJveV", "9fXzAADRtfX2VtX2xpYl9kZXBzX3dlYmlkbF9iaW5kZXIDBCFfX2VtX2pzX19hcnJheV9ib3VuZHNfY2hlY", "2tfZXJyb3IDBRlfX2luZGlyZWN0X2Z1bmN0aW9uX3RhYmxlAQAQX19lcnJub19sb2NhdGlvbgAPBmZmbHVz", "aAAtBm1hbGxvYwARBGZyZWUAEhVlbXNjcmlwdGVuX3N0YWNrX2luaXQAKRllbXNjcmlwdGVuX3N0YWNrX2d", "ldF9mcmVlACoZZW1zY3JpcHRlbl9zdGFja19nZXRfYmFzZQArGGVtc2NyaXB0ZW5fc3RhY2tfZ2V0X2VuZA", "AsCXN0YWNrU2F2ZQAlDHN0YWNrUmVzdG9yZQAmCnN0YWNrQWxsb2MAJxxlbXNjcmlwdGVuX3N0YWNrX2dld", "F9jdXJyZW50ACgTX19zdGFydF9lbV9saWJfZGVwcwMGEl9fc3RvcF9lbV9saWJfZGVwcwMHDV9fc3RhcnRf", "ZW1fanMDCAxfX3N0b3BfZW1fanMDCQxkeW5DYWxsX2ppamkALwmJgICAAAEAQQELAxYYGgqtkYGAACwEABA", "pC81IAvcCf6EFfiMAIQNBgAEhBCADIARrIQUgBSAANgJ8IAUgATYCeCAFIAI2AnQgBSgCfCEGIAUoAnghBy", "AFIAc2AnAgBSgCdCEIIAghCSAJrCH6AiAGKQMIIfsCIPsCIPoCfCH8AiAGIPwCNwMIIAYpAwAh/QJCfyH+A", "iD9AiD+AoUh/wIgBSD/AjcDaEIAIYADIAUggAM3A2AgBSgCdCEKIAUoAnQhC0EgIQwgCyAMbyENIAogDWsh", "DiAFIA42AlwgBSgCXCEPQcAAIRAgDyERIBAhEiARIBJPIRNBASEUIBMgFHEhFQJAIBVFDQAgBSgCcCEWIAU", "gFjYCWEIAIYEDIAUggQM3A1BCACGCAyAFIIIDNwNIQgAhgwMgBSCDAzcDQEIAIYQDIAUghAM3AzggBSkDYC", "GFAyAFKAJcIRcgFyEYIBitIYYDIIUDIIYDfCGHA0IgIYgDIIcDIIgDfSGJAyAFIIkDNwMwIAUoAlwhGSAFK", "AJ0IRogGiAZayEbIAUgGzYCdCAFKQNoIYoDIAUgigM3A1ACQANAIAUpA2AhiwMgBSkDMCGMAyCLAyGNAyCM", "AyGOAyCNAyCOA1QhHEEBIR0gHCAdcSEeIB5FDQEgBSgCWCEfIB8pAwAhjwMgBSkDUCGQAyCPAyCQA4UhkQM", "gBSCRAzcDKCAFKAJYISAgICkDCCGSAyAFKQNIIZMDIJIDIJMDhSGUAyAFIJQDNwMgIAUoAlghISAhKQMQIZ", "UDIAUpA0AhlgMglQMglgOFIZcDIAUglwM3AxggBSgCWCEiICIpAxghmAMgBSkDOCGZAyCYAyCZA4UhmgMgB", "SCaAzcDECAFKQMoIZsDQv8BIZwDIJsDIJwDgyGdA0KADiGeAyCdAyCeA3whnwMgnwOnISNBgIDAAiEkQQMh", "JSAjICV0ISYgJCAmaiEnICcpAwAhoAMgBSCgAzcDUCAFKQMoIaEDQgghogMgoQMgogOIIaMDIAUgowM3Ayg", "gBSkDICGkA0L/ASGlAyCkAyClA4MhpgNCgA4hpwMgpgMgpwN8IagDIKgDpyEoQYCAwAIhKUEDISogKCAqdC", "ErICkgK2ohLCAsKQMAIakDIAUgqQM3A0ggBSkDICGqA0IIIasDIKoDIKsDiCGsAyAFIKwDNwMgIAUpAxghr", "QNC/wEhrgMgrQMgrgODIa8DQoAOIbADIK8DILADfCGxAyCxA6chLUGAgMACIS5BAyEvIC0gL3QhMCAuIDBq", "ITEgMSkDACGyAyAFILIDNwNAIAUpAxghswNCCCG0AyCzAyC0A4ghtQMgBSC1AzcDGCAFKQMQIbYDQv8BIbc", "DILYDILcDgyG4A0KADiG5AyC4AyC5A3whugMgugOnITJBgIDAAiEzQQMhNCAyIDR0ITUgMyA1aiE2IDYpAw", "AhuwMgBSC7AzcDOCAFKQMQIbwDQgghvQMgvAMgvQOIIb4DIAUgvgM3AxAgBSkDKCG/A0L/ASHAAyC/AyDAA", "4MhwQNCgAwhwgMgwQMgwgN8IcMDIMMDpyE3QYCAwAIhOEEDITkgNyA5dCE6IDggOmohOyA7KQMAIcQDIAUp", "A1AhxQMgxQMgxAOFIcYDIAUgxgM3A1AgBSkDKCHHA0IIIcgDIMcDIMgDiCHJAyAFIMkDNwMoIAUpAyAhygN", "C/wEhywMgygMgywODIcwDQoAMIc0DIMwDIM0DfCHOAyDOA6chPEGAgMACIT1BAyE+IDwgPnQhPyA9ID9qIU", "AgQCkDACHPAyAFKQNIIdADINADIM8DhSHRAyAFINEDNwNIIAUpAyAh0gNCCCHTAyDSAyDTA4gh1AMgBSDUA", "zcDICAFKQMYIdUDQv8BIdYDINUDINYDgyHXA0KADCHYAyDXAyDYA3wh2QMg2QOnIUFBgIDAAiFCQQMhQyBB", "IEN0IUQgQiBEaiFFIEUpAwAh2gMgBSkDQCHbAyDbAyDaA4Uh3AMgBSDcAzcDQCAFKQMYId0DQggh3gMg3QM", "g3gOIId8DIAUg3wM3AxggBSkDECHgA0L/ASHhAyDgAyDhA4Mh4gNCgAwh4wMg4gMg4wN8IeQDIOQDpyFGQY", "CAwAIhR0EDIUggRiBIdCFJIEcgSWohSiBKKQMAIeUDIAUpAzgh5gMg5gMg5QOFIecDIAUg5wM3AzggBSkDE", "CHoA0IIIekDIOgDIOkDiCHqAyAFIOoDNwMQIAUpAygh6wNC/wEh7AMg6wMg7AODIe0DQoAKIe4DIO0DIO4D", "fCHvAyDvA6chS0GAgMACIUxBAyFNIEsgTXQhTiBMIE5qIU8gTykDACHwAyAFKQNQIfEDIPEDIPADhSHyAyA", "FIPIDNwNQIAUpAygh8wNCCCH0AyDzAyD0A4gh9QMgBSD1AzcDKCAFKQMgIfYDQv8BIfcDIPYDIPcDgyH4A0", "KACiH5AyD4AyD5A3wh+gMg+gOnIVBBgIDAAiFRQQMhUiBQIFJ0IVMgUSBTaiFUIFQpAwAh+wMgBSkDSCH8A", "yD8AyD7A4Uh/QMgBSD9AzcDSCAFKQMgIf4DQggh/wMg/gMg/wOIIYAEIAUggAQ3AyAgBSkDGCGBBEL/ASGC", "BCCBBCCCBIMhgwRCgAohhAQggwQghAR8IYUEIIUEpyFVQYCAwAIhVkEDIVcgVSBXdCFYIFYgWGohWSBZKQM", "AIYYEIAUpA0AhhwQghwQghgSFIYgEIAUgiAQ3A0AgBSkDGCGJBEIIIYoEIIkEIIoEiCGLBCAFIIsENwMYIA", "UpAxAhjARC/wEhjQQgjAQgjQSDIY4EQoAKIY8EII4EII8EfCGQBCCQBKchWkGAgMACIVtBAyFcIFogXHQhX", "SBbIF1qIV4gXikDACGRBCAFKQM4IZIEIJIEIJEEhSGTBCAFIJMENwM4IAUpAxAhlARCCCGVBCCUBCCVBIgh", "lgQgBSCWBDcDECAFKQMoIZcEQv8BIZgEIJcEIJgEgyGZBEKACCGaBCCZBCCaBHwhmwQgmwSnIV9BgIDAAiF", "gQQMhYSBfIGF0IWIgYCBiaiFjIGMpAwAhnAQgBSkDUCGdBCCdBCCcBIUhngQgBSCeBDcDUCAFKQMoIZ8EQg", "ghoAQgnwQgoASIIaEEIAUgoQQ3AyggBSkDICGiBEL/ASGjBCCiBCCjBIMhpARCgAghpQQgpAQgpQR8IaYEI", "KYEpyFkQYCAwAIhZUEDIWYgZCBmdCFnIGUgZ2ohaCBoKQMAIacEIAUpA0ghqAQgqAQgpwSFIakEIAUgqQQ3", "A0ggBSkDICGqBEIIIasEIKoEIKsEiCGsBCAFIKwENwMgIAUpAxghrQRC/wEhrgQgrQQgrgSDIa8EQoAIIbA", "EIK8EILAEfCGxBCCxBKchaUGAgMACIWpBAyFrIGkga3QhbCBqIGxqIW0gbSkDACGyBCAFKQNAIbMEILMEIL", "IEhSG0BCAFILQENwNAIAUpAxghtQRCCCG2BCC1BCC2BIghtwQgBSC3BDcDGCAFKQMQIbgEQv8BIbkEILgEI", "LkEgyG6BEKACCG7BCC6BCC7BHwhvAQgvASnIW5BgIDAAiFvQQMhcCBuIHB0IXEgbyBxaiFyIHIpAwAhvQQg", "BSkDOCG+BCC+BCC9BIUhvwQgBSC/BDcDOCAFKQMQIcAEQgghwQQgwAQgwQSIIcIEIAUgwgQ3AxAgBSkDKCH", "DBEL/ASHEBCDDBCDEBIMhxQRCgAYhxgQgxQQgxgR8IccEIMcEpyFzQYCAwAIhdEEDIXUgcyB1dCF2IHQgdm", "ohdyB3KQMAIcgEIAUpA1AhyQQgyQQgyASFIcoEIAUgygQ3A1AgBSkDKCHLBEIIIcwEIMsEIMwEiCHNBCAFI", "M0ENwMoIAUpAyAhzgRC/wEhzwQgzgQgzwSDIdAEQoAGIdEEINAEINEEfCHSBCDSBKcheEGAgMACIXlBAyF6", "IHggenQheyB5IHtqIXwgfCkDACHTBCAFKQNIIdQEINQEINMEhSHVBCAFINUENwNIIAUpAyAh1gRCCCHXBCD", "WBCDXBIgh2AQgBSDYBDcDICAFKQMYIdkEQv8BIdoEINkEINoEgyHbBEKABiHcBCDbBCDcBHwh3QQg3QSnIX", "1BgIDAAiF+QQMhfyB9IH90IYABIH4ggAFqIYEBIIEBKQMAId4EIAUpA0Ah3wQg3wQg3gSFIeAEIAUg4AQ3A", "0AgBSkDGCHhBEIIIeIEIOEEIOIEiCHjBCAFIOMENwMYIAUpAxAh5ARC/wEh5QQg5AQg5QSDIeYEQoAGIecE", "IOYEIOcEfCHoBCDoBKchggFBgIDAAiGDAUEDIYQBIIIBIIQBdCGFASCDASCFAWohhgEghgEpAwAh6QQgBSk", "DOCHqBCDqBCDpBIUh6wQgBSDrBDcDOCAFKQMQIewEQggh7QQg7AQg7QSIIe4EIAUg7gQ3AxAgBSkDKCHvBE", "L/ASHwBCDvBCDwBIMh8QRCgAQh8gQg8QQg8gR8IfMEIPMEpyGHAUGAgMACIYgBQQMhiQEghwEgiQF0IYoBI", "IgBIIoBaiGLASCLASkDACH0BCAFKQNQIfUEIPUEIPQEhSH2BCAFIPYENwNQIAUpAygh9wRCCCH4BCD3BCD4", "BIgh+QQgBSD5BDcDKCAFKQMgIfoEQv8BIfsEIPoEIPsEgyH8BEKABCH9BCD8BCD9BHwh/gQg/gSnIYwBQYC", "AwAIhjQFBAyGOASCMASCOAXQhjwEgjQEgjwFqIZABIJABKQMAIf8EIAUpA0ghgAUggAUg/wSFIYEFIAUggQ", "U3A0ggBSkDICGCBUIIIYMFIIIFIIMFiCGEBSAFIIQFNwMgIAUpAxghhQVC/wEhhgUghQUghgWDIYcFQoAEI", "YgFIIcFIIgFfCGJBSCJBachkQFBgIDAAiGSAUEDIZMBIJEBIJMBdCGUASCSASCUAWohlQEglQEpAwAhigUg", "BSkDQCGLBSCLBSCKBYUhjAUgBSCMBTcDQCAFKQMYIY0FQgghjgUgjQUgjgWIIY8FIAUgjwU3AxggBSkDECG", "QBUL/ASGRBSCQBSCRBYMhkgVCgAQhkwUgkgUgkwV8IZQFIJQFpyGWAUGAgMACIZcBQQMhmAEglgEgmAF0IZ", "kBIJcBIJkBaiGaASCaASkDACGVBSAFKQM4IZYFIJYFIJUFhSGXBSAFIJcFNwM4IAUpAxAhmAVCCCGZBSCYB", "SCZBYghmgUgBSCaBTcDECAFKQMoIZsFQv8BIZwFIJsFIJwFgyGdBUKAAiGeBSCdBSCeBXwhnwUgnwWnIZsB", "QYCAwAIhnAFBAyGdASCbASCdAXQhngEgnAEgngFqIZ8BIJ8BKQMAIaAFIAUpA1AhoQUgoQUgoAWFIaIFIAU", "gogU3A1AgBSkDKCGjBUIIIaQFIKMFIKQFiCGlBSAFIKUFNwMoIAUpAyAhpgVC/wEhpwUgpgUgpwWDIagFQo", "ACIakFIKgFIKkFfCGqBSCqBachoAFBgIDAAiGhAUEDIaIBIKABIKIBdCGjASChASCjAWohpAEgpAEpAwAhq", "wUgBSkDSCGsBSCsBSCrBYUhrQUgBSCtBTcDSCAFKQMgIa4FQgghrwUgrgUgrwWIIbAFIAUgsAU3AyAgBSkD", "GCGxBUL/ASGyBSCxBSCyBYMhswVCgAIhtAUgswUgtAV8IbUFILUFpyGlAUGAgMACIaYBQQMhpwEgpQEgpwF", "0IagBIKYBIKgBaiGpASCpASkDACG2BSAFKQNAIbcFILcFILYFhSG4BSAFILgFNwNAIAUpAxghuQVCCCG6BS", "C5BSC6BYghuwUgBSC7BTcDGCAFKQMQIbwFQv8BIb0FILwFIL0FgyG+BUKAAiG/BSC+BSC/BXwhwAUgwAWnI", "aoBQYCAwAIhqwFBAyGsASCqASCsAXQhrQEgqwEgrQFqIa4BIK4BKQMAIcEFIAUpAzghwgUgwgUgwQWFIcMF", "IAUgwwU3AzggBSkDECHEBUIIIcUFIMQFIMUFiCHGBSAFIMYFNwMQIAUpAyghxwVC/wEhyAUgxwUgyAWDIck", "FQgAhygUgyQUgygV8IcsFIMsFpyGvAUGAgMACIbABQQMhsQEgrwEgsQF0IbIBILABILIBaiGzASCzASkDAC", "HMBSAFKQNQIc0FIM0FIMwFhSHOBSAFIM4FNwNQIAUpAyAhzwVC/wEh0AUgzwUg0AWDIdEFQgAh0gUg0QUg0", "gV8IdMFINMFpyG0AUGAgMACIbUBQQMhtgEgtAEgtgF0IbcBILUBILcBaiG4ASC4ASkDACHUBSAFKQNIIdUF", "INUFINQFhSHWBSAFINYFNwNIIAUpAxgh1wVC/wEh2AUg1wUg2AWDIdkFQgAh2gUg2QUg2gV8IdsFINsFpyG", "5AUGAgMACIboBQQMhuwEguQEguwF0IbwBILoBILwBaiG9ASC9ASkDACHcBSAFKQNAId0FIN0FINwFhSHeBS", "AFIN4FNwNAIAUpAxAh3wVC/wEh4AUg3wUg4AWDIeEFQgAh4gUg4QUg4gV8IeMFIOMFpyG+AUGAgMACIb8BQ", "QMhwAEgvgEgwAF0IcEBIL8BIMEBaiHCASDCASkDACHkBSAFKQM4IeUFIOUFIOQFhSHmBSAFIOYFNwM4IAUp", "A2Ah5wVCICHoBSDnBSDoBXwh6QUgBSDpBTcDYCAFKAJYIcMBQSAhxAEgwwEgxAFqIcUBIAUgxQE2AlgMAAs", "AC0IAIeoFIAUg6gU3A2ggBSgCWCHGASDGASkDACHrBSAFKQNQIewFIOsFIOwFhSHtBSAFKQNoIe4FIO4FIO", "0FhSHvBSAFIO8FNwNoIAUpA2gh8AVCCCHxBSDwBSDxBYgh8gUgBSkDaCHzBUL/ASH0BSDzBSD0BYMh9QUg9", "QWnIccBQYCAwQIhyAFBAyHJASDHASDJAXQhygEgyAEgygFqIcsBIMsBKQMAIfYFIPIFIPYFhSH3BSAFIPcF", "NwNoIAUpA2gh+AVCCCH5BSD4BSD5BYgh+gUgBSkDaCH7BUL/ASH8BSD7BSD8BYMh/QUg/QWnIcwBQYCAwQI", "hzQFBAyHOASDMASDOAXQhzwEgzQEgzwFqIdABINABKQMAIf4FIPoFIP4FhSH/BSAFIP8FNwNoIAUpA2ghgA", "ZCCCGBBiCABiCBBoghggYgBSkDaCGDBkL/ASGEBiCDBiCEBoMhhQYghQanIdEBQYCAwQIh0gFBAyHTASDRA", "SDTAXQh1AEg0gEg1AFqIdUBINUBKQMAIYYGIIIGIIYGhSGHBiAFIIcGNwNoIAUpA2ghiAZCCCGJBiCIBiCJ", "BoghigYgBSkDaCGLBkL/ASGMBiCLBiCMBoMhjQYgjQanIdYBQYCAwQIh1wFBAyHYASDWASDYAXQh2QEg1wE", "g2QFqIdoBINoBKQMAIY4GIIoGII4GhSGPBiAFII8GNwNoIAUpA2ghkAZCCCGRBiCQBiCRBoghkgYgBSkDaC", "GTBkL/ASGUBiCTBiCUBoMhlQYglQanIdsBQYCAwQIh3AFBAyHdASDbASDdAXQh3gEg3AEg3gFqId8BIN8BK", "QMAIZYGIJIGIJYGhSGXBiAFIJcGNwNoIAUpA2ghmAZCCCGZBiCYBiCZBoghmgYgBSkDaCGbBkL/ASGcBiCb", "BiCcBoMhnQYgnQanIeABQYCAwQIh4QFBAyHiASDgASDiAXQh4wEg4QEg4wFqIeQBIOQBKQMAIZ4GIJoGIJ4", "GhSGfBiAFIJ8GNwNoIAUpA2ghoAZCCCGhBiCgBiChBoghogYgBSkDaCGjBkL/ASGkBiCjBiCkBoMhpQYgpQ", "anIeUBQYCAwQIh5gFBAyHnASDlASDnAXQh6AEg5gEg6AFqIekBIOkBKQMAIaYGIKIGIKYGhSGnBiAFIKcGN", "wNoIAUpA2ghqAZCCCGpBiCoBiCpBoghqgYgBSkDaCGrBkL/ASGsBiCrBiCsBoMhrQYgrQanIeoBQYCAwQIh", "6wFBAyHsASDqASDsAXQh7QEg6wEg7QFqIe4BIO4BKQMAIa4GIKoGIK4GhSGvBiAFIK8GNwNoIAUoAlgh7wE", "g7wEpAwghsAYgBSkDSCGxBiCwBiCxBoUhsgYgBSkDaCGzBiCzBiCyBoUhtAYgBSC0BjcDaCAFKQNoIbUGQg", "ghtgYgtQYgtgaIIbcGIAUpA2ghuAZC/wEhuQYguAYguQaDIboGILoGpyHwAUGAgMECIfEBQQMh8gEg8AEg8", "gF0IfMBIPEBIPMBaiH0ASD0ASkDACG7BiC3BiC7BoUhvAYgBSC8BjcDaCAFKQNoIb0GQgghvgYgvQYgvgaI", "Ib8GIAUpA2ghwAZC/wEhwQYgwAYgwQaDIcIGIMIGpyH1AUGAgMECIfYBQQMh9wEg9QEg9wF0IfgBIPYBIPg", "BaiH5ASD5ASkDACHDBiC/BiDDBoUhxAYgBSDEBjcDaCAFKQNoIcUGQgghxgYgxQYgxgaIIccGIAUpA2ghyA", "ZC/wEhyQYgyAYgyQaDIcoGIMoGpyH6AUGAgMECIfsBQQMh/AEg+gEg/AF0If0BIPsBIP0BaiH+ASD+ASkDA", "CHLBiDHBiDLBoUhzAYgBSDMBjcDaCAFKQNoIc0GQgghzgYgzQYgzgaIIc8GIAUpA2gh0AZC/wEh0QYg0AYg", "0QaDIdIGINIGpyH/AUGAgMECIYACQQMhgQIg/wEggQJ0IYICIIACIIICaiGDAiCDAikDACHTBiDPBiDTBoU", "h1AYgBSDUBjcDaCAFKQNoIdUGQggh1gYg1QYg1gaIIdcGIAUpA2gh2AZC/wEh2QYg2AYg2QaDIdoGINoGpy", "GEAkGAgMECIYUCQQMhhgIghAIghgJ0IYcCIIUCIIcCaiGIAiCIAikDACHbBiDXBiDbBoUh3AYgBSDcBjcDa", "CAFKQNoId0GQggh3gYg3QYg3gaIId8GIAUpA2gh4AZC/wEh4QYg4AYg4QaDIeIGIOIGpyGJAkGAgMECIYoC", "QQMhiwIgiQIgiwJ0IYwCIIoCIIwCaiGNAiCNAikDACHjBiDfBiDjBoUh5AYgBSDkBjcDaCAFKQNoIeUGQgg", "h5gYg5QYg5gaIIecGIAUpA2gh6AZC/wEh6QYg6AYg6QaDIeoGIOoGpyGOAkGAgMECIY8CQQMhkAIgjgIgkA", "J0IZECII8CIJECaiGSAiCSAikDACHrBiDnBiDrBoUh7AYgBSDsBjcDaCAFKQNoIe0GQggh7gYg7QYg7gaII", "e8GIAUpA2gh8AZC/wEh8QYg8AYg8QaDIfIGIPIGpyGTAkGAgMECIZQCQQMhlQIgkwIglQJ0IZYCIJQCIJYC", "aiGXAiCXAikDACHzBiDvBiDzBoUh9AYgBSD0BjcDaCAFKAJYIZgCIJgCKQMQIfUGIAUpA0Ah9gYg9QYg9ga", "FIfcGIAUpA2gh+AYg+AYg9waFIfkGIAUg+QY3A2ggBSkDaCH6BkIIIfsGIPoGIPsGiCH8BiAFKQNoIf0GQv", "8BIf4GIP0GIP4GgyH/BiD/BqchmQJBgIDBAiGaAkEDIZsCIJkCIJsCdCGcAiCaAiCcAmohnQIgnQIpAwAhg", "Acg/AYggAeFIYEHIAUggQc3A2ggBSkDaCGCB0IIIYMHIIIHIIMHiCGEByAFKQNoIYUHQv8BIYYHIIUHIIYH", "gyGHByCHB6chngJBgIDBAiGfAkEDIaACIJ4CIKACdCGhAiCfAiChAmohogIgogIpAwAhiAcghAcgiAeFIYk", "HIAUgiQc3A2ggBSkDaCGKB0IIIYsHIIoHIIsHiCGMByAFKQNoIY0HQv8BIY4HII0HII4HgyGPByCPB6chow", "JBgIDBAiGkAkEDIaUCIKMCIKUCdCGmAiCkAiCmAmohpwIgpwIpAwAhkAcgjAcgkAeFIZEHIAUgkQc3A2ggB", "SkDaCGSB0IIIZMHIJIHIJMHiCGUByAFKQNoIZUHQv8BIZYHIJUHIJYHgyGXByCXB6chqAJBgIDBAiGpAkED", "IaoCIKgCIKoCdCGrAiCpAiCrAmohrAIgrAIpAwAhmAcglAcgmAeFIZkHIAUgmQc3A2ggBSkDaCGaB0IIIZs", "HIJoHIJsHiCGcByAFKQNoIZ0HQv8BIZ4HIJ0HIJ4HgyGfByCfB6chrQJBgIDBAiGuAkEDIa8CIK0CIK8CdC", "GwAiCuAiCwAmohsQIgsQIpAwAhoAcgnAcgoAeFIaEHIAUgoQc3A2ggBSkDaCGiB0IIIaMHIKIHIKMHiCGkB", "yAFKQNoIaUHQv8BIaYHIKUHIKYHgyGnByCnB6chsgJBgIDBAiGzAkEDIbQCILICILQCdCG1AiCzAiC1Amoh", "tgIgtgIpAwAhqAcgpAcgqAeFIakHIAUgqQc3A2ggBSkDaCGqB0IIIasHIKoHIKsHiCGsByAFKQNoIa0HQv8", "BIa4HIK0HIK4HgyGvByCvB6chtwJBgIDBAiG4AkEDIbkCILcCILkCdCG6AiC4AiC6AmohuwIguwIpAwAhsA", "cgrAcgsAeFIbEHIAUgsQc3A2ggBSkDaCGyB0IIIbMHILIHILMHiCG0ByAFKQNoIbUHQv8BIbYHILUHILYHg", "yG3ByC3B6chvAJBgIDBAiG9AkEDIb4CILwCIL4CdCG/AiC9AiC/AmohwAIgwAIpAwAhuAcgtAcguAeFIbkH", "IAUguQc3A2ggBSgCWCHBAiDBAikDGCG6ByAFKQM4IbsHILoHILsHhSG8ByAFKQNoIb0HIL0HILwHhSG+ByA", "FIL4HNwNoIAUpA2ghvwdCCCHAByC/ByDAB4ghwQcgBSkDaCHCB0L/ASHDByDCByDDB4MhxAcgxAenIcICQY", "CAwQIhwwJBAyHEAiDCAiDEAnQhxQIgwwIgxQJqIcYCIMYCKQMAIcUHIMEHIMUHhSHGByAFIMYHNwNoIAUpA", "2ghxwdCCCHIByDHByDIB4ghyQcgBSkDaCHKB0L/ASHLByDKByDLB4MhzAcgzAenIccCQYCAwQIhyAJBAyHJ", "AiDHAiDJAnQhygIgyAIgygJqIcsCIMsCKQMAIc0HIMkHIM0HhSHOByAFIM4HNwNoIAUpA2ghzwdCCCHQByD", "PByDQB4gh0QcgBSkDaCHSB0L/ASHTByDSByDTB4Mh1Acg1AenIcwCQYCAwQIhzQJBAyHOAiDMAiDOAnQhzw", "IgzQIgzwJqIdACINACKQMAIdUHINEHINUHhSHWByAFINYHNwNoIAUpA2gh1wdCCCHYByDXByDYB4gh2QcgB", "SkDaCHaB0L/ASHbByDaByDbB4Mh3Acg3AenIdECQYCAwQIh0gJBAyHTAiDRAiDTAnQh1AIg0gIg1AJqIdUC", "INUCKQMAId0HINkHIN0HhSHeByAFIN4HNwNoIAUpA2gh3wdCCCHgByDfByDgB4gh4QcgBSkDaCHiB0L/ASH", "jByDiByDjB4Mh5Acg5AenIdYCQYCAwQIh1wJBAyHYAiDWAiDYAnQh2QIg1wIg2QJqIdoCINoCKQMAIeUHIO", "EHIOUHhSHmByAFIOYHNwNoIAUpA2gh5wdCCCHoByDnByDoB4gh6QcgBSkDaCHqB0L/ASHrByDqByDrB4Mh7", "Acg7AenIdsCQYCAwQIh3AJBAyHdAiDbAiDdAnQh3gIg3AIg3gJqId8CIN8CKQMAIe0HIOkHIO0HhSHuByAF", "IO4HNwNoIAUpA2gh7wdCCCHwByDvByDwB4gh8QcgBSkDaCHyB0L/ASHzByDyByDzB4Mh9Acg9AenIeACQYC", "AwQIh4QJBAyHiAiDgAiDiAnQh4wIg4QIg4wJqIeQCIOQCKQMAIfUHIPEHIPUHhSH2ByAFIPYHNwNoIAUpA2", "gh9wdCCCH4ByD3ByD4B4gh+QcgBSkDaCH6B0L/ASH7ByD6ByD7B4Mh/Acg/AenIeUCQYCAwQIh5gJBAyHnA", "iDlAiDnAnQh6AIg5gIg6AJqIekCIOkCKQMAIf0HIPkHIP0HhSH+ByAFIP4HNwNoIAUpA2Ah/wdCICGACCD/", "ByCACHwhgQggBSCBCDcDYAtCACGCCCAFIIIINwMIAkADQCAFKQMIIYMIIAUoAnQh6gIg6gIh6wIg6wKsIYQ", "IIIMIIYUIIIQIIYYIIIUIIIYIVCHsAkEBIe0CIOwCIO0CcSHuAiDuAkUNASAFKQNoIYcIQgghiAgghwggiA", "iIIYkIIAUpA2ghigggBSgCcCHvAiAFKQNgIYsIIIsIpyHwAiDvAiDwAmoh8QIg8QItAAAh8gJB/wEh8wIg8", "gIg8wJxIfQCIPQCrSGMCCCKCCCMCIUhjQhC/wEhjgggjQggjgiDIY8III8IpyH1AkGAgMECIfYCQQMh9wIg", "9QIg9wJ0IfgCIPYCIPgCaiH5AiD5AikDACGQCCCJCCCQCIUhkQggBSCRCDcDaCAFKQMIIZIIQgEhkwggkgg", "gkwh8IZQIIAUglAg3AwggBSkDYCGVCEIBIZYIIJUIIJYIfCGXCCAFIJcINwNgDAALAAsgBSkDaCGYCEJ/IZ", "kIIJgIIJkIhSGaCCAGIJoINwMADwudAgIcfwV+IwAhBEEgIQUgBCAFayEGIAYkACAGIAA2AhwgBiABNgIYI", "AYgAjYCFCAGIAM2AhAgBigCHCEHIAYoAhghCCAGKAIUIQkgByAIIAkQBiAGKAIQIQogBiAKNgIMQQAhCyAG", "IAs2AggCQANAIAYoAgghDEEIIQ0gDCEOIA0hDyAOIA9JIRBBASERIBAgEXEhEiASRQ0BIAcpAwAhICAGKAI", "IIRNBAyEUIBMgFHQhFSAVIRYgFq0hISAgICGIISJC/wEhIyAiICODISQgJKchFyAGKAIMIRggBigCCCEZIB", "ggGWohGiAaIBc6AAAgBigCCCEbQQEhHCAbIBxqIR0gBiAdNgIIDAALAAtBICEeIAYgHmohHyAfJAAPC14BD", "H8jACEBQRAhAiABIAJrIQMgAyQAIAMgADYCDCADKAIMIQRBACEFIAQhBiAFIQcgBiAHRiEIQQEhCSAIIAlx", "IQoCQCAKDQAgBBAUC0EQIQsgAyALaiEMIAwkAA8LNQIEfwF+QRAhACAAEBMhAUIAIQQgASAENwMAQQghAiA", "BIAJqIQMgAyAENwMAIAEQChogAQ8LPAIEfwJ+IwAhAUEQIQIgASACayEDIAMgADYCDCADKAIMIQRCACEFIA", "QgBTcDAEIAIQYgBCAGNwMIIAQPC1kBCH8jACEDQRAhBCADIARrIQUgBSQAIAUgADYCDCAFIAE2AgggBSACN", "gIEIAUoAgwhBiAFKAIIIQcgBSgCBCEIIAYgByAIEAZBECEJIAUgCWohCiAKJAAPC2kBCX8jACEEQRAhBSAE", "IAVrIQYgBiQAIAYgADYCDCAGIAE2AgggBiACNgIEIAYgAzYCACAGKAIMIQcgBigCCCEIIAYoAgQhCSAGKAI", "AIQogByAIIAkgChAHQRAhCyAGIAtqIQwgDCQADwteAQx/IwAhAUEQIQIgASACayEDIAMkACADIAA2AgwgAy", "gCDCEEQQAhBSAEIQYgBSEHIAYgB0YhCEEBIQkgCCAJcSEKAkAgCg0AIAQQFAtBECELIAMgC2ohDCAMJAAPC", "wcAPwBBEHQLBwBBlJLBAgtUAQJ/QQAoAoCQwQIiASAAQQdqQXhxIgJqIQACQAJAIAJFDQAgACABTQ0BCwJA", "IAAQDk0NACAAEAFFDQELQQAgADYCgJDBAiABDwsQD0EwNgIAQX8LviwBC38jAEEQayIBJAACQAJAAkACQAJ", "AAkACQAJAAkACQAJAAkACQAJAAkAgAEH0AUsNAAJAQQAoApiSwQIiAkEQIABBC2pBeHEgAEELSRsiA0EDdi", "IEdiIAQQNxRQ0AAkACQCAAQX9zQQFxIARqIgVBA3QiBEHAksECaiIAIARByJLBAmooAgAiBCgCCCIDRw0AQ", "QAgAkF+IAV3cTYCmJLBAgwBCyADIAA2AgwgACADNgIICyAEQQhqIQAgBCAFQQN0IgVBA3I2AgQgBCAFaiIE", "IAQoAgRBAXI2AgQMDwsgA0EAKAKgksECIgZNDQECQCAARQ0AAkACQCAAIAR0QQIgBHQiAEEAIABrcnEiAEE", "AIABrcWgiBEEDdCIAQcCSwQJqIgUgAEHIksECaigCACIAKAIIIgdHDQBBACACQX4gBHdxIgI2ApiSwQIMAQ", "sgByAFNgIMIAUgBzYCCAsgACADQQNyNgIEIAAgA2oiByAEQQN0IgQgA2siBUEBcjYCBCAAIARqIAU2AgACQ", "CAGRQ0AIAZBeHFBwJLBAmohA0EAKAKsksECIQQCQAJAIAJBASAGQQN2dCIIcQ0AQQAgAiAIcjYCmJLBAiAD", "IQgMAQsgAygCCCEICyADIAQ2AgggCCAENgIMIAQgAzYCDCAEIAg2AggLIABBCGohAEEAIAc2AqySwQJBACA", "FNgKgksECDA8LQQAoApySwQIiCUUNASAJQQAgCWtxaEECdEHIlMECaigCACIHKAIEQXhxIANrIQQgByEFAk", "ADQAJAIAUoAhAiAA0AIAVBFGooAgAiAEUNAgsgACgCBEF4cSADayIFIAQgBSAESSIFGyEEIAAgByAFGyEHI", "AAhBQwACwALIAcoAhghCgJAIAcoAgwiCCAHRg0AIAcoAggiAEEAKAKoksECSRogACAINgIMIAggADYCCAwO", "CwJAIAdBFGoiBSgCACIADQAgBygCECIARQ0DIAdBEGohBQsDQCAFIQsgACIIQRRqIgUoAgAiAA0AIAhBEGo", "hBSAIKAIQIgANAAsgC0EANgIADA0LQX8hAyAAQb9/Sw0AIABBC2oiAEF4cSEDQQAoApySwQIiBkUNAEEAIQ", "sCQCADQYACSQ0AQR8hCyADQf///wdLDQAgA0EmIABBCHZnIgBrdkEBcSAAQQF0a0E+aiELC0EAIANrIQQCQ", "AJAAkACQCALQQJ0QciUwQJqKAIAIgUNAEEAIQBBACEIDAELQQAhACADQQBBGSALQQF2ayALQR9GG3QhB0EA", "IQgDQAJAIAUoAgRBeHEgA2siAiAETw0AIAIhBCAFIQggAg0AQQAhBCAFIQggBSEADAMLIAAgBUEUaigCACI", "CIAIgBSAHQR12QQRxakEQaigCACIFRhsgACACGyEAIAdBAXQhByAFDQALCwJAIAAgCHINAEEAIQhBAiALdC", "IAQQAgAGtyIAZxIgBFDQMgAEEAIABrcWhBAnRByJTBAmooAgAhAAsgAEUNAQsDQCAAKAIEQXhxIANrIgIgB", "EkhBwJAIAAoAhAiBQ0AIABBFGooAgAhBQsgAiAEIAcbIQQgACAIIAcbIQggBSEAIAUNAAsLIAhFDQAgBEEA", "KAKgksECIANrTw0AIAgoAhghCwJAIAgoAgwiByAIRg0AIAgoAggiAEEAKAKoksECSRogACAHNgIMIAcgADY", "CCAwMCwJAIAhBFGoiBSgCACIADQAgCCgCECIARQ0DIAhBEGohBQsDQCAFIQIgACIHQRRqIgUoAgAiAA0AIA", "dBEGohBSAHKAIQIgANAAsgAkEANgIADAsLAkBBACgCoJLBAiIAIANJDQBBACgCrJLBAiEEAkACQCAAIANrI", "gVBEEkNAEEAIAU2AqCSwQJBACAEIANqIgc2AqySwQIgByAFQQFyNgIEIAQgAGogBTYCACAEIANBA3I2AgQM", "AQtBAEEANgKsksECQQBBADYCoJLBAiAEIABBA3I2AgQgBCAAaiIAIAAoAgRBAXI2AgQLIARBCGohAAwNCwJ", "AQQAoAqSSwQIiByADTQ0AQQAgByADayIENgKkksECQQBBACgCsJLBAiIAIANqIgU2ArCSwQIgBSAEQQFyNg", "IEIAAgA0EDcjYCBCAAQQhqIQAMDQsCQAJAQQAoAvCVwQJFDQBBACgC+JXBAiEEDAELQQBCfzcC/JXBAkEAQ", "oCggICAgAQ3AvSVwQJBACABQQxqQXBxQdiq1aoFczYC8JXBAkEAQQA2AoSWwQJBAEEANgLUlcECQYAgIQQL", "QQAhACAEIANBL2oiBmoiAkEAIARrIgtxIgggA00NDEEAIQACQEEAKALQlcECIgRFDQBBACgCyJXBAiIFIAh", "qIgkgBU0NDSAJIARLDQ0LAkACQEEALQDUlcECQQRxDQACQAJAAkACQAJAQQAoArCSwQIiBEUNAEHYlcECIQ", "ADQAJAIAAoAgAiBSAESw0AIAUgACgCBGogBEsNAwsgACgCCCIADQALC0EAEBAiB0F/Rg0DIAghAgJAQQAoA", "vSVwQIiAEF/aiIEIAdxRQ0AIAggB2sgBCAHakEAIABrcWohAgsgAiADTQ0DAkBBACgC0JXBAiIARQ0AQQAo", "AsiVwQIiBCACaiIFIARNDQQgBSAASw0ECyACEBAiACAHRw0BDAULIAIgB2sgC3EiAhAQIgcgACgCACAAKAI", "EakYNASAHIQALIABBf0YNAQJAIANBMGogAksNACAAIQcMBAsgBiACa0EAKAL4lcECIgRqQQAgBGtxIgQQEE", "F/Rg0BIAQgAmohAiAAIQcMAwsgB0F/Rw0CC0EAQQAoAtSVwQJBBHI2AtSVwQILIAgQECEHQQAQECEAIAdBf", "0YNBSAAQX9GDQUgByAATw0FIAAgB2siAiADQShqTQ0FC0EAQQAoAsiVwQIgAmoiADYCyJXBAgJAIABBACgC", "zJXBAk0NAEEAIAA2AsyVwQILAkACQEEAKAKwksECIgRFDQBB2JXBAiEAA0AgByAAKAIAIgUgACgCBCIIakY", "NAiAAKAIIIgANAAwFCwALAkACQEEAKAKoksECIgBFDQAgByAATw0BC0EAIAc2AqiSwQILQQAhAEEAIAI2At", "yVwQJBACAHNgLYlcECQQBBfzYCuJLBAkEAQQAoAvCVwQI2ArySwQJBAEEANgLklcECA0AgAEEDdCIEQciSw", "QJqIARBwJLBAmoiBTYCACAEQcySwQJqIAU2AgAgAEEBaiIAQSBHDQALQQAgAkFYaiIAQXggB2tBB3FBACAH", "QQhqQQdxGyIEayIFNgKkksECQQAgByAEaiIENgKwksECIAQgBUEBcjYCBCAHIABqQSg2AgRBAEEAKAKAlsE", "CNgK0ksECDAQLIAAtAAxBCHENAiAEIAVJDQIgBCAHTw0CIAAgCCACajYCBEEAIARBeCAEa0EHcUEAIARBCG", "pBB3EbIgBqIgU2ArCSwQJBAEEAKAKkksECIAJqIgcgAGsiADYCpJLBAiAFIABBAXI2AgQgBCAHakEoNgIEQ", "QBBACgCgJbBAjYCtJLBAgwDC0EAIQgMCgtBACEHDAgLAkAgB0EAKAKoksECIghPDQBBACAHNgKoksECIAch", "CAsgByACaiEFQdiVwQIhAAJAAkACQAJAA0AgACgCACAFRg0BIAAoAggiAA0ADAILAAsgAC0ADEEIcUUNAQt", "B2JXBAiEAA0ACQCAAKAIAIgUgBEsNACAFIAAoAgRqIgUgBEsNAwsgACgCCCEADAALAAsgACAHNgIAIAAgAC", "gCBCACajYCBCAHQXggB2tBB3FBACAHQQhqQQdxG2oiCyADQQNyNgIEIAVBeCAFa0EHcUEAIAVBCGpBB3Eba", "iICIAsgA2oiA2shAAJAIAIgBEcNAEEAIAM2ArCSwQJBAEEAKAKkksECIABqIgA2AqSSwQIgAyAAQQFyNgIE", "DAgLAkAgAkEAKAKsksECRw0AQQAgAzYCrJLBAkEAQQAoAqCSwQIgAGoiADYCoJLBAiADIABBAXI2AgQgAyA", "AaiAANgIADAgLIAIoAgQiBEEDcUEBRw0GIARBeHEhBgJAIARB/wFLDQAgAigCCCIFIARBA3YiCEEDdEHAks", "ECaiIHRhoCQCACKAIMIgQgBUcNAEEAQQAoApiSwQJBfiAId3E2ApiSwQIMBwsgBCAHRhogBSAENgIMIAQgB", "TYCCAwGCyACKAIYIQkCQCACKAIMIgcgAkYNACACKAIIIgQgCEkaIAQgBzYCDCAHIAQ2AggMBQsCQCACQRRq", "IgUoAgAiBA0AIAIoAhAiBEUNBCACQRBqIQULA0AgBSEIIAQiB0EUaiIFKAIAIgQNACAHQRBqIQUgBygCECI", "EDQALIAhBADYCAAwEC0EAIAJBWGoiAEF4IAdrQQdxQQAgB0EIakEHcRsiCGsiCzYCpJLBAkEAIAcgCGoiCD", "YCsJLBAiAIIAtBAXI2AgQgByAAakEoNgIEQQBBACgCgJbBAjYCtJLBAiAEIAVBJyAFa0EHcUEAIAVBWWpBB", "3EbakFRaiIAIAAgBEEQakkbIghBGzYCBCAIQRBqQQApAuCVwQI3AgAgCEEAKQLYlcECNwIIQQAgCEEIajYC", "4JXBAkEAIAI2AtyVwQJBACAHNgLYlcECQQBBADYC5JXBAiAIQRhqIQADQCAAQQc2AgQgAEEIaiEHIABBBGo", "hACAHIAVJDQALIAggBEYNACAIIAgoAgRBfnE2AgQgBCAIIARrIgdBAXI2AgQgCCAHNgIAAkAgB0H/AUsNAC", "AHQXhxQcCSwQJqIQACQAJAQQAoApiSwQIiBUEBIAdBA3Z0IgdxDQBBACAFIAdyNgKYksECIAAhBQwBCyAAK", "AIIIQULIAAgBDYCCCAFIAQ2AgwgBCAANgIMIAQgBTYCCAwBC0EfIQACQCAHQf///wdLDQAgB0EmIAdBCHZn", "IgBrdkEBcSAAQQF0a0E+aiEACyAEIAA2AhwgBEIANwIQIABBAnRByJTBAmohBQJAAkACQEEAKAKcksECIgh", "BASAAdCICcQ0AQQAgCCACcjYCnJLBAiAFIAQ2AgAgBCAFNgIYDAELIAdBAEEZIABBAXZrIABBH0YbdCEAIA", "UoAgAhCANAIAgiBSgCBEF4cSAHRg0CIABBHXYhCCAAQQF0IQAgBSAIQQRxaiICQRBqKAIAIggNAAsgAkEQa", "iAENgIAIAQgBTYCGAsgBCAENgIMIAQgBDYCCAwBCyAFKAIIIgAgBDYCDCAFIAQ2AgggBEEANgIYIAQgBTYC", "DCAEIAA2AggLQQAoAqSSwQIiACADTQ0AQQAgACADayIENgKkksECQQBBACgCsJLBAiIAIANqIgU2ArCSwQI", "gBSAEQQFyNgIEIAAgA0EDcjYCBCAAQQhqIQAMCAsQD0EwNgIAQQAhAAwHC0EAIQcLIAlFDQACQAJAIAIgAi", "gCHCIFQQJ0QciUwQJqIgQoAgBHDQAgBCAHNgIAIAcNAUEAQQAoApySwQJBfiAFd3E2ApySwQIMAgsgCUEQQ", "RQgCSgCECACRhtqIAc2AgAgB0UNAQsgByAJNgIYAkAgAigCECIERQ0AIAcgBDYCECAEIAc2AhgLIAJBFGoo", "AgAiBEUNACAHQRRqIAQ2AgAgBCAHNgIYCyAGIABqIQAgAiAGaiICKAIEIQQLIAIgBEF+cTYCBCADIABBAXI", "2AgQgAyAAaiAANgIAAkAgAEH/AUsNACAAQXhxQcCSwQJqIQQCQAJAQQAoApiSwQIiBUEBIABBA3Z0IgBxDQ", "BBACAFIAByNgKYksECIAQhAAwBCyAEKAIIIQALIAQgAzYCCCAAIAM2AgwgAyAENgIMIAMgADYCCAwBC0EfI", "QQCQCAAQf///wdLDQAgAEEmIABBCHZnIgRrdkEBcSAEQQF0a0E+aiEECyADIAQ2AhwgA0IANwIQIARBAnRB", "yJTBAmohBQJAAkACQEEAKAKcksECIgdBASAEdCIIcQ0AQQAgByAIcjYCnJLBAiAFIAM2AgAgAyAFNgIYDAE", "LIABBAEEZIARBAXZrIARBH0YbdCEEIAUoAgAhBwNAIAciBSgCBEF4cSAARg0CIARBHXYhByAEQQF0IQQgBS", "AHQQRxaiIIQRBqKAIAIgcNAAsgCEEQaiADNgIAIAMgBTYCGAsgAyADNgIMIAMgAzYCCAwBCyAFKAIIIgAgA", "zYCDCAFIAM2AgggA0EANgIYIAMgBTYCDCADIAA2AggLIAtBCGohAAwCCwJAIAtFDQACQAJAIAggCCgCHCIF", "QQJ0QciUwQJqIgAoAgBHDQAgACAHNgIAIAcNAUEAIAZBfiAFd3EiBjYCnJLBAgwCCyALQRBBFCALKAIQIAh", "GG2ogBzYCACAHRQ0BCyAHIAs2AhgCQCAIKAIQIgBFDQAgByAANgIQIAAgBzYCGAsgCEEUaigCACIARQ0AIA", "dBFGogADYCACAAIAc2AhgLAkACQCAEQQ9LDQAgCCAEIANqIgBBA3I2AgQgCCAAaiIAIAAoAgRBAXI2AgQMA", "QsgCCADQQNyNgIEIAggA2oiByAEQQFyNgIEIAcgBGogBDYCAAJAIARB/wFLDQAgBEF4cUHAksECaiEAAkAC", "QEEAKAKYksECIgVBASAEQQN2dCIEcQ0AQQAgBSAEcjYCmJLBAiAAIQQMAQsgACgCCCEECyAAIAc2AgggBCA", "HNgIMIAcgADYCDCAHIAQ2AggMAQtBHyEAAkAgBEH///8HSw0AIARBJiAEQQh2ZyIAa3ZBAXEgAEEBdGtBPm", "ohAAsgByAANgIcIAdCADcCECAAQQJ0QciUwQJqIQUCQAJAAkAgBkEBIAB0IgNxDQBBACAGIANyNgKcksECI", "AUgBzYCACAHIAU2AhgMAQsgBEEAQRkgAEEBdmsgAEEfRht0IQAgBSgCACEDA0AgAyIFKAIEQXhxIARGDQIg", "AEEddiEDIABBAXQhACAFIANBBHFqIgJBEGooAgAiAw0ACyACQRBqIAc2AgAgByAFNgIYCyAHIAc2AgwgByA", "HNgIIDAELIAUoAggiACAHNgIMIAUgBzYCCCAHQQA2AhggByAFNgIMIAcgADYCCAsgCEEIaiEADAELAkAgCk", "UNAAJAAkAgByAHKAIcIgVBAnRByJTBAmoiACgCAEcNACAAIAg2AgAgCA0BQQAgCUF+IAV3cTYCnJLBAgwCC", "yAKQRBBFCAKKAIQIAdGG2ogCDYCACAIRQ0BCyAIIAo2AhgCQCAHKAIQIgBFDQAgCCAANgIQIAAgCDYCGAsg", "B0EUaigCACIARQ0AIAhBFGogADYCACAAIAg2AhgLAkACQCAEQQ9LDQAgByAEIANqIgBBA3I2AgQgByAAaiI", "AIAAoAgRBAXI2AgQMAQsgByADQQNyNgIEIAcgA2oiBSAEQQFyNgIEIAUgBGogBDYCAAJAIAZFDQAgBkF4cU", "HAksECaiEDQQAoAqySwQIhAAJAAkBBASAGQQN2dCIIIAJxDQBBACAIIAJyNgKYksECIAMhCAwBCyADKAIII", "QgLIAMgADYCCCAIIAA2AgwgACADNgIMIAAgCDYCCAtBACAFNgKsksECQQAgBDYCoJLBAgsgB0EIaiEACyAB", "QRBqJAAgAAuDDQEHfwJAIABFDQAgAEF4aiIBIABBfGooAgAiAkF4cSIAaiEDAkAgAkEBcQ0AIAJBA3FFDQE", "gASABKAIAIgJrIgFBACgCqJLBAiIESQ0BIAIgAGohAAJAAkACQCABQQAoAqySwQJGDQACQCACQf8BSw0AIA", "EoAggiBCACQQN2IgVBA3RBwJLBAmoiBkYaAkAgASgCDCICIARHDQBBAEEAKAKYksECQX4gBXdxNgKYksECD", "AULIAIgBkYaIAQgAjYCDCACIAQ2AggMBAsgASgCGCEHAkAgASgCDCIGIAFGDQAgASgCCCICIARJGiACIAY2", "AgwgBiACNgIIDAMLAkAgAUEUaiIEKAIAIgINACABKAIQIgJFDQIgAUEQaiEECwNAIAQhBSACIgZBFGoiBCg", "CACICDQAgBkEQaiEEIAYoAhAiAg0ACyAFQQA2AgAMAgsgAygCBCICQQNxQQNHDQJBACAANgKgksECIAMgAk", "F+cTYCBCABIABBAXI2AgQgAyAANgIADwtBACEGCyAHRQ0AAkACQCABIAEoAhwiBEECdEHIlMECaiICKAIAR", "w0AIAIgBjYCACAGDQFBAEEAKAKcksECQX4gBHdxNgKcksECDAILIAdBEEEUIAcoAhAgAUYbaiAGNgIAIAZF", "DQELIAYgBzYCGAJAIAEoAhAiAkUNACAGIAI2AhAgAiAGNgIYCyABQRRqKAIAIgJFDQAgBkEUaiACNgIAIAI", "gBjYCGAsgASADTw0AIAMoAgQiAkEBcUUNAAJAAkACQAJAAkAgAkECcQ0AAkAgA0EAKAKwksECRw0AQQAgAT", "YCsJLBAkEAQQAoAqSSwQIgAGoiADYCpJLBAiABIABBAXI2AgQgAUEAKAKsksECRw0GQQBBADYCoJLBAkEAQ", "QA2AqySwQIPCwJAIANBACgCrJLBAkcNAEEAIAE2AqySwQJBAEEAKAKgksECIABqIgA2AqCSwQIgASAAQQFy", "NgIEIAEgAGogADYCAA8LIAJBeHEgAGohAAJAIAJB/wFLDQAgAygCCCIEIAJBA3YiBUEDdEHAksECaiIGRho", "CQCADKAIMIgIgBEcNAEEAQQAoApiSwQJBfiAFd3E2ApiSwQIMBQsgAiAGRhogBCACNgIMIAIgBDYCCAwECy", "ADKAIYIQcCQCADKAIMIgYgA0YNACADKAIIIgJBACgCqJLBAkkaIAIgBjYCDCAGIAI2AggMAwsCQCADQRRqI", "gQoAgAiAg0AIAMoAhAiAkUNAiADQRBqIQQLA0AgBCEFIAIiBkEUaiIEKAIAIgINACAGQRBqIQQgBigCECIC", "DQALIAVBADYCAAwCCyADIAJBfnE2AgQgASAAQQFyNgIEIAEgAGogADYCAAwDC0EAIQYLIAdFDQACQAJAIAM", "gAygCHCIEQQJ0QciUwQJqIgIoAgBHDQAgAiAGNgIAIAYNAUEAQQAoApySwQJBfiAEd3E2ApySwQIMAgsgB0", "EQQRQgBygCECADRhtqIAY2AgAgBkUNAQsgBiAHNgIYAkAgAygCECICRQ0AIAYgAjYCECACIAY2AhgLIANBF", "GooAgAiAkUNACAGQRRqIAI2AgAgAiAGNgIYCyABIABBAXI2AgQgASAAaiAANgIAIAFBACgCrJLBAkcNAEEA", "IAA2AqCSwQIPCwJAIABB/wFLDQAgAEF4cUHAksECaiECAkACQEEAKAKYksECIgRBASAAQQN2dCIAcQ0AQQA", "gBCAAcjYCmJLBAiACIQAMAQsgAigCCCEACyACIAE2AgggACABNgIMIAEgAjYCDCABIAA2AggPC0EfIQICQC", "AAQf///wdLDQAgAEEmIABBCHZnIgJrdkEBcSACQQF0a0E+aiECCyABIAI2AhwgAUIANwIQIAJBAnRByJTBA", "mohBAJAAkACQAJAQQAoApySwQIiBkEBIAJ0IgNxDQBBACAGIANyNgKcksECIAQgATYCACABIAQ2AhgMAQsg", "AEEAQRkgAkEBdmsgAkEfRht0IQIgBCgCACEGA0AgBiIEKAIEQXhxIABGDQIgAkEddiEGIAJBAXQhAiAEIAZ", "BBHFqIgNBEGooAgAiBg0ACyADQRBqIAE2AgAgASAENgIYCyABIAE2AgwgASABNgIIDAELIAQoAggiACABNg", "IMIAQgATYCCCABQQA2AhggASAENgIMIAEgADYCCAtBAEEAKAK4ksECQX9qIgFBfyABGzYCuJLBAgsLMQEBf", "yAAQQEgABshAQJAA0AgARARIgANAQJAECIiAEUNACAAEQMADAELCxAAAAsgAAsGACAAEBILBAAgAAsLACAA", "KAI8EBUQAgsVAAJAIAANAEEADwsQDyAANgIAQX8L4wIBB38jAEEgayIDJAAgAyAAKAIcIgQ2AhAgACgCFCE", "FIAMgAjYCHCADIAE2AhggAyAFIARrIgE2AhQgASACaiEGIANBEGohBEECIQcCQAJAAkACQAJAIAAoAjwgA0", "EQakECIANBDGoQAxAXRQ0AIAQhBQwBCwNAIAYgAygCDCIBRg0CAkAgAUF/Sg0AIAQhBQwECyAEIAEgBCgCB", "CIISyIJQQN0aiIFIAUoAgAgASAIQQAgCRtrIghqNgIAIARBDEEEIAkbaiIEIAQoAgAgCGs2AgAgBiABayEG", "IAUhBCAAKAI8IAUgByAJayIHIANBDGoQAxAXRQ0ACwsgBkF/Rw0BCyAAIAAoAiwiATYCHCAAIAE2AhQgACA", "BIAAoAjBqNgIQIAIhAQwBC0EAIQEgAEEANgIcIABCADcDECAAIAAoAgBBIHI2AgAgB0ECRg0AIAIgBSgCBG", "shAQsgA0EgaiQAIAELNwEBfyMAQRBrIgMkACAAIAEgAkH/AXEgA0EIahAwEBchAiADKQMIIQEgA0EQaiQAQ", "n8gASACGwsNACAAKAI8IAEgAhAZCwIACwIACw4AQZCWwQIQG0GUlsECCwkAQZCWwQIQHAsEAEEBCwIACwcA", "IAAoAgALCQBBnJbBAhAhCwYAIAAkAQsEACMBCwQAIwALBgAgACQACxIBAn8jACAAa0FwcSIBJAAgAQsEACM", "ACxMAQYCAwAIkA0EAQQ9qQXBxJAILBwAjACMCawsEACMDCwQAIwILuAIBA38CQCAADQBBACEBAkBBACgCmJ", "bBAkUNAEEAKAKYlsECEC0hAQsCQEEAKAKYkcECRQ0AQQAoApiRwQIQLSABciEBCwJAEB0oAgAiAEUNAANAQ", "QAhAgJAIAAoAkxBAEgNACAAEB8hAgsCQCAAKAIUIAAoAhxGDQAgABAtIAFyIQELAkAgAkUNACAAECALIAAo", "AjgiAA0ACwsQHiABDwtBACECAkAgACgCTEEASA0AIAAQHyECCwJAAkACQCAAKAIUIAAoAhxGDQAgAEEAQQA", "gACgCJBEHABogACgCFA0AQX8hASACDQEMAgsCQCAAKAIEIgEgACgCCCIDRg0AIAAgASADa6xBASAAKAIoEQ", "QAGgtBACEBIABBADYCHCAAQgA3AxAgAEIANwIEIAJFDQELIAAQIAsgAQsNACABIAIgAyAAEQQACyMBAX4gA", "CABIAKtIAOtQiCGhCAEEC4hBSAFQiCIpxAjIAWnCxMAIAAgAacgAUIgiKcgAiADEAQLC7aSgYAABABBgIDA", "AguAkAEAAAAAAAAAADGyfhfBM8W4CfdqdtFBU0U4RRRhEHKW/RLu1eyig6aKI1yr+2OwYzIbGb+ac8L1zyq", "rwY2y8TB3T088gRYhlCF+/UKW1xJRmUa4VvfHYMdkdwoo4AZTAtxdoelttKIyq2wTl3p1kfcTVFaDG2XjYe", "5l5P0MpNCkVp6eeAItQihDrywGFexx7fuXaRJ0/AN7BqbbbGM9ML6+jHCt7o/Bjsm9wtP5TvJLcYWHx5heg", "N2MtDW5j5+zGDTR0USDO2O8YuBjOpT6UHna2CYu9eoi7yfplFDiKxEqn8M/kW+Z4Bro8o3veFjT31DKyPsZ", "SKFJrft6hQ6JkowVPD3xBFqEUIYNj48Tm7eVPjXKm3KLxQPDBHjlZUr2xnsu0yTo+Af2DB9hWv85NDO0JyR", "OnilGpUkWljCJ6HVg8XNyzYVMpcSnQsCzko2WAR96hafzneSX4ks32eRc11JaYZwYae4mYi1QLmZ+LxWnlW", "hrch8/ZzFoWdkMCP5U9NCio4kGd8Z4xZMR9xG29b19q1TjcKaHK4Ca5p1nZ7TuOLBNXOrVRd5Pgf8i/RR2G", "/e5ujacBASNCogISIvFN0iy7ey1h2Hn7OTcXsuQoNQpXOQb3/Gwpr+h1amh5nGVehn/AmBrw2RKbs6wHnwC", "V4/W9vUKHRIlGSvHR3QK0xbckxPpdVHnLng4IlsLRiYdvYAaHh8nNm8rfSusYTD3XO7FAQegvUWt3rIwtd6", "qhJ4bCgjwysuU7I33OUK03FXfSE9cpknQ8Q/sGW0UN8cwPCmhVVEjpiBOv1xk412x4X165E5InDxTjEqTf/", "riK5K/jytHv/ZKgs0Z1nYNiF1D/txujXcNU8psUHu8xXNEC1+Vw4SAZyUbLQM+tTIZMtoexoafmdi/aO/28", "a4rpqip3DNJlm6yybmupbSn3MzeeJ1gDMI4MdLcTcRa84pPxR1+AeLLz1ukDQyXH/p9JbPMP1Kn0NbkPn7O", "YtDhZJopv/2naNkhjkivjzGV6JPwX2689C0v1IRVvaoovh5m+kJ8me0GJiPuI2zre/sXkZA0rdi+Qz06Ubk", "fKY40DIgvrt4aS4w0zTvPzmjdcQV/RdgPWxjJYJu41KuLvJ9RKcbDarh5J2ls0qJ6yu/aWN6stbv5KmJydW", "04CQgaFUPHEy/IO9+te4IHTthJSVBKMHlZGXqM6LFK/FeQ6AD9gPiCQFHbxUW4vZYhQalTuIkP6DaAmpYAo", "6QpuzJrpneSFles81hjz6pTQ83jKvUym+E92iIZMIr+BcDWhsmU3M+3vsFH+lFk9/KqoFeIx5nGQNS3lrsC", "IezrFTokSjJW3VlrLeV59+7lHH9M9QthE9SuAVs0OKSrJtLros5d8HAXYJW1D241yC8lgdQfHKM1Hpf/w94", "vZo00PD5ObN5W+gWOQFmt7ZNCPctUOL2fBb8MeSovfKzAB2md1yPYfGRRWC+pNBlPoelgar1VCT03FFHYw0", "LIDvKse3MCz3r/wttKwXzYu8wHY3KEaLmrvpGeQzYWrmqNVCa4TJOg4x/YM4n+7bciLB2Lsbv51jJei3aAC", "YfB821OzqqiRkxBnH65mxA4W4CvuwGjVSw6kN0t/JLnUi1R7uhE9wOvIfU+TBLGsdE2NA2Jqv70xVckfx9X", "z0a7QOVM2u/l7XrNV73qmNRfBNqWji8g7BoQu4b8ud3dqG6sR898ZRrvGqaU2aD2K11ksVXqZU4TGHDQRZj", "zsyKqDseEqzYLCAHPSjZaBnw5s7Fd92nDxAH2pTznG1U5METbKyYokIFVoCYngvg012QSWDBDy/FvXFdMUV", "O5Z5Jt5TJGkoqiKkdO88sge5JddvyN3OFIV+VOuZm98TrBGH8L56owCQSghHFipLmbiLW1wxyzeKhNDY2GC", "NJo2tvwvDR2xanpHkiWn7dIGxguP6ctyV/aK+uHn2jdPspZfXqu2qMpC2q4wss+XiWvuhyU+owgMm6J2SzC", "yTRTfvtP0fN7SkS/yIpp2dCLyQ05uh7oYvXezAp/ptAn4b/ceOlb4ZWfqB1LLOM1O57zKXOISASJ4OToQE3", "wPMz0hfgy2w0NfoqSOQEetSfVSx+L8C7CFmc1CErD63ouIiFpWrF9hx+QX36bgrg/enSicj9SHGlLxtxl/m", "HZ0XODyATuE08sQjG2Ey8gipRomneendG641koCYlc4n9bYW0d6EyQ6aZQ32P/jaMsHqul5vEEMaALmheY5", "sUCZbOiUoyH1XDzTpPg8pAUQzb2uUszHaayBoGI+U0KZ4HDObC8WWt381XEgQ4nfLbAkHzk6tpwEhA0KtVY", "pGfTI/GS7R2wBsNRZ2/cr84RAmKi1/YED5ywk5Kgx7Zxi3GgVxj/82XqYdLB5c5BG/2g4QRdCQZv93P32M4", "4tBHgssQddgDxBYGitouLMUN7lmOFTjMb6Lob0XR+RCpaxAwQR7v8Eh/QbQA1LQEjra56wQbouUZJU3Zl1k", "zvd/stYaTliVdPvjkAtJcfqn4MRxd1pNoSVKeGmsdV6mVlFfiNBmYv3V1Q7OwWFLkgbOKS+9cnfJiXmBf1X", "rXwjaYqaeKfhjU1nm99g4/0o8iv3QOUTsdmcIV2whn8NlYHtMS8Dj0Fk7+MgahvLXcFQr0z1njsRMD62Ncr", "dEiUZKzpZVVjiaehFNEgQQKZ1Tfp4JI/FVjm8lHKOf6Y6hfCJvuLgI8rJAeew86U7jtWkWPyfOr5+mVU2wA", "AAAAAAAAASEfgaLc09/b7HVeJPU832bNat+GKe8Avnag5Sii4t4bV79kin4xAcGa1bsMV94BfLvKOq6LDd6", "lRwuTMA1a2ORmFBKS0YkHPqt+zRT4ZgeDimFMtiS12Fsxq3YYr7gG/hC097pza9kk3d4oPFqE2Zn8wamehl", "cGQooTJmQesbHPqwynxsJibhVmZnhA641uqEd5+eI3XrFw/LPDTLxTb9XdrELuYICwDxDGnWhJb7CyMdkcy", "pW8b2vNGLVUE+tpKuwHNPbPOLbwIW3rcObXtk0AcmrSOgRplbu4UHyxCbcwmqfR3m3aaOpXzQ5YRDVoV3bS", "j/qY5reNECZMzD1jZ5gxOc1u4bC4QvxTEujIX7j/3UyTShSMZydmhqnkn4G5gkeZKEZDUmZYivP3wGq9ZuW", "r7HZitm65PFct3/wwOb99djJeXuzqYKe7WIHYxQVgGppHAHoZ1r/CIY061JLbYWcAkrt2Tgi+vc34ZPBn57", "4A7OflUrs0YduaNWqoI9LWVrsq6wr/AQmMdkA0jNbuCTFXX7UuCj3W6eyVj4CBMAhMzYoOIl3j15YA4NGkd", "AzXKyH/UAao3wjy3T75mC6IDrP8IXg68lvRaTFLp7zbtNHUEFQmHgdnDgyrnhywjGrQqYqBnRJQuQ9zR+tC", "lHlWD85m9MM2pYXQF44GxP02Wa/mrxlFX+qKcDxic5rZw2VwgUNsG3sftq9Z+KYh1ZS7cfzZuaB3SGiuJhT", "Tf/Fhh66bNcz+U71UcULJDVfNOwN3A+gS1m/n0KjZJXgJ6c4/qGQEZ4hLEux3vL+tsuWZ4akZnrIzR0Uyds", "NT2OzBbN12fnLHbWOwDqmlBBXimSjoHiglCmM79DvB8uhgvL3d1MFPyX89HwEHHpdytQexigrAMlOqhhNW2", "R/onsBZlX82H1W/39g3o+XAjEMecaklssbNYgHwC/lhGRevay+N0I4Zqo50ri8MXcZyNb6UgYdQGNcUoRUj", "W4PHDdnLyqVybMew+NRLB66/GGqeIIgxCzrIf78/CZPX6RelclXWFf4GFxhTSle3ItXIwOiAbRmp2BZlyZ/", "su3ULyb8E9TM9XOTJAiXqsp+ANxbb2SsbAQZgEJr4NJqj2rPPQDVeRSXzXM/9FEHEhy+PECWvi/4ppILOgI", "6Uf4t4URFaQ/6gDVG+Eedi4SGvjW3OPBQzrlUVi3mxNSwv98lYpmv4RvBx4Lem1tlZcdM8ZHkOYpNLfbdpp", "6tDjMrfa7p4cY7mFVlCVXjMr/mU+56GpxVTOD1lGNGhVHInvMfEAn6Ov01jQe3tfjOeUuLjMT6h6yWY2E26", "M39OBIdZ72bgoJTJ7YZpTw+gKejyB8uT3H/ytkPQnyQoOxuXXFE9+PvkwVo2jrvRFOR8eykPGQ3HO6TA4zW", "3hsrlAeH8tBVaGTrbLJZrk3P2OmYNieoxryXlv/FIQ68pcuP+0FfCDfWhPCQdPR2L3E48mTwinCkAneNBh+", "imh4uQPeSm9yclV0PiPmud+KN+rOKDSoJ5AaJ/PVg8UPb7OpmK1R1Pd1nmSlUP0CWo38+lVbLxOil9E3aKa", "krwE9OYe1TPa++ScUSoixWmhU33bUeLqIeazFWxlFRxe1tlyzfDUjBaRORp6xCN6pcuO+/C/41XtjG6TR4s", "Uo8N+4DjlSGMKizkAUFJ8lPw4Y7ex2AdU03AkV9lvM6Ml6ZlnFMZS1yCh3od8cWYg1hKEMJ37HeD5WsPQ9U", "wpFw90MV5e7upgpjx2vjZZ3pdQjywJ19OlV3/Ha+m/ZJGgibhbg9jFBGEZ8BxjsHIwlu9DRtRR+EtWwAsBN", "DlPf6E2JfO6ku281p9ttFr6Woghad7u7RvQ8+FGlqkNc2fHFrBLHa6Nwf67UwNaTuV2ykylsAD5BPyxjIr4", "RxlsS4V7fNa1l8fpRgzVnvJ3r15y+yMtqMBO1Ak7DGXvICZjPcz6Gt9KQcKoDWpSmKopdZz6nOHCHcj/5zq", "zqYX9oEjTzUWHd3ML6hC67M8wk2NdJE0afGokgtdfjTU0LcTqYGt6w04RRRiEnGU/BlalcDOoksm1DBKRud", "NS5v1L8vkO56UQ07l8Uqwk0rmb/pw6GxAlTyikK9uRa+VgYOPLsyZfEpYf06HUh8rTBleUQbww/iTw5M72X", "bqF5N+siRY1DbETKYJ7mJ6vcmSAyjx49hhGk3Z5Zs8Xkj1TWTEhL38lCaSv7JWMgYMwCUyk0mzpNAT+uheI", "2wi+fz6VX887YAlLyWNxPbXLq4i+yjl6VaMcvEk8iiDiQpbHiRPCZwIqIfN+5b1XaE2AZr919RCIJTdSSIN", "GSj/EvSmIrA4N36wKHX9aIP9RB6jeCPNouLFvH+r/BdviBo6VkT8qk6Xm5iKlyNwKGNYri8S82UJfNkM88E", "sv8QWBoraLiwC5QmHKAb989pew72GjfAtf3/cPCRRI/KlsrbjonjM8hiTqWIApB8twW9oy54iSCuATndKPP", "6b9FqDHZW613T056ICFBgLpys/GcgutoCq9Zo4168UXHkqQPW9cJJ1lir91KLxMKlF9SaicH7KMaNCq4Nv/", "2jtcJ1xTgUg7sSfncxvGqFMGExCFNTQm+KTQZyx9c8aQE+SQ2s4pcXGZn1D1hm6RGS6rpwP5Xvt+jz5mk7E", "ZGxY4CpFlAkOs97JxUUpKBEyfBUWmvGT2wjSnhtEVLLEiXBCyJuOf65W9msnmzNesddUt/RE6AAAAAAAAAA", "BdMxKlPcGwcbpmJEp7gmHj51U270ZD0ZIfXt/MpSIa8kJtzWmY46qDpTj7ht6gexH4C+kj42HLYFUvKcEYY", "+3QCBw7ZCWiXaHvSQ2LY+GMM7J6Hy5eIDxCSnH2Db1B9yIXQuSogIBHU/AX0kfGw5bBrSTA4vsCJrDBzcXa", "YuADlZz+139fIbPke6vhkBliYnYmmPM1JKPSB96TGhbHwhlng6AIs/oDqRZk9T5cvEB4hDnGLPmBgcj1lOL", "sG3qD7kXJ0f6+R0JeNC6EyFEBAY+mc7fa9DzAP9eLvDPX36H0t9aPIXLiYETGMdoXnaQjlVRs6QU4meIlJe", "kIHO2W5t4etDsOSKsnbm9Tbjin7WS//Q5dKgLQpQ+M9lbDITPExOyrZdGEDgV0nUww52tIRqUPEQP1znWHF", "X68JzUsjoUzzuEUJ4mzRIO/BkERZvUHUi1bcgPDyMbiXKN56uArpyk8/kr4RRZmmU0ZH86qUCVI30Qs3A9t", "5PiuKMXZN/QG3Yt19suSycdt+pKj/X2PhLxoz5Dv2LJFDBk3mwb7USTHeWqoFF5s5XcIjf0isSqmpprQzjA", "UF2cW633q8PbsZTBbINniU9GkgCrHjNS8l+dRuJq/xhmqJuHJYrQvOklHKqk/hz2fdIaa2NjSC3AyxUtKhe", "EZ1Q8E+zvSETjaLc29PY8iKn8QDA1MaHcckFZP3N41RA41a45sr81P5xaI76fPkHz1s7UuF753KcNc823GL", "Coa0fnOrHZdhz4RGzWuUO3aDQO+CG/gnD1YNVFOLDEOYGsn9HPtgX+YYM7XkIxKH8VT3HKtTfpuIgbqnesO", "K/x/Nfg41s+bjRPc/QBPLb6oTu/vpXLsDtmputlKNK/fS/SJy+8Jbm86DIIizOoPpFpRsTBp184UK7bkBoa", "RjcW569cUI6xMdchG89TBV05TeBvAxmRqj+MJ/JXwiyzMMpuhpuIuEQ2C6lmtCw3ybEmKBJ4ZqM+t+fvjyy", "9Hie4oab74PeK0L5gYOxkkN7srYyNmKjaShurTUoF/AH3AqQLA3EwS2P1osrEkR/v7Hgl50Xl06V4jyMmgn", "iHfsWWLGDLDEs0UWEqoQ242DfajSI7zMwUfU56JPoLUUCm82MrvEIljOxnlC19hcWjSOgZqlAEsW8CfO6sk", "cMsO9nB96PXilj3k1UApRZP61OHt2ctgtqfn80jkCtDHQLLFp6JJAVUdgdcCn4ixJOWKPiF86XpEuLkshEE", "oyjVf7BprB2sbpwLfCM46qqvWr/vILMGojWbyyNqJ/Gk9FxWd7Ga6KuyFSK7+w4frXPSwpRfgZIqXlO2WBU", "VZSyflCsMzqh8I9ndX8CEPIslGBqQjcLRbmnt7+RBiEWZbywoeRVT+IBgamEN2Rlsd2arpu32veP64YYnmT", "r3dw3nR+AEbizKFOgBqXCiZl7j7sBvxDFl1Q/mWq6w/S9B+OCbaS2p9Pzh790gWWW+aBbpHOe5Shrnm24xZ", "s2GUHNsaPChUNKLznVntugkHsFagmF3LZe61bjl6eO443afLBLvIn9+IkSRC+BkNgruDgX85qXx6sGqinFh", "iHCeDeAehmdJtwNZO6OfaA/+d5VxN2huzjjDBnK8hGZU+bfKOChzYJU+Kp7jlWpv03deUqkBnWkSsL59DY4", "Q7j8xyrFHGufo/vZX5Zyn/ue4vyMp1jMJ4Xl5NK2xZzXylZRAYfvzwvRUU901IE7b+xIaqflq2iz9091J1s", "5VoXr+XD0ahMFWfD+boE5ffE9zedLUghXouHW4FGARFmNUfSLVFN1c96N74xKJiYdKunSlW/1Fzd5NcmScH", "WppUcD1SR1ppiPFN/OI2vTy+Hgu/M6TgD6y7Nn6D1YzmqYOvnKbw0dW7JpJdFoE2gI3J1B7HE2uzn2zp33d", "ik7h2Twq+vALOi2TqN38McyneUgVxPN3hdO1AoEz9bZDZyYBCt/9LIIT6kueKPvtRY6+kCMx9KsM+nLat8b", "yassaXX44S3VHSm6RNKy8c4aN88XvEaV8wMSHCaWFUnoBAdjJIbnZXxkYrAVrLS5Z2N8xUbCQN1aelkWd+g", "TAUF9RpbJei03XctDRfhQfutGzF0wqz6Kj3vVeOOaFNlTYNJiMdYa9uNCuWfi5zClP1m+eZe0XlFbZKdcRI", "V0Aod/oEPEO+Y8sWMWRhcKzG9teBFYYlmimwlFCH2xaIjI1V4Pa3/420FLfF0+rMnxEpdnWiDZmp/m81pDB", "QqrtbUvQUQaihUnixld8h9ZJA3YxUb1ASx3Yyyhe+wk/0ZJf31g6z4tCkdQzUKAO/47bQMRWYcli2gD93Vk", "ngBYWSmkqX+ZH9jnu5qfYy8aC9aRyUN4KAR+hf89J0UxIa201W77XjY586VIPgsRhYwglGJt1wqCklXHDJm", "zN5u3hvYmym8snKgGSLT0WTAqrdV5nqeFKy2zoCrwU+EWNJZzG9oAPQ0zjKFX1C+NL1iJcmb+fFE0X5cHNZ", "CINQlGstQEutvpEkGtVLoo5d8O96iHiwK2AxXwtvLYbEJnKOmTIelGEbsz7oXveRWYJRG80DxIP8v5CrvOS", "RtRP503ouuaKntsQSyl9BqU6VJ3MBPxyaXDAasrFO+89q31zxYNym/Hh6YTDQrQvYuJiaMvYdVuuqPafzRm", "yxvpzS4bCX/uyNjnfccSePFIZnVD8Q7O9JtXXxAtFcnq7gQx5Eko0M89NRu3lTPX0AAAAAAAAAAF6RFQ9Ib", "Nu/17G8RsP+b0uJIKlJi5K09K5jeY2G/d+W8PJsgs6RBCl50sXLRQOw3SdD0MQNb2tiN1RlQl7dZhlpxXBN", "FrG9puDl2QSdIwlSvnTMC9VP0u2ZNxzP2CC5j8emCcCQTGIwToagiRve1sQQF7WGU7INe26oyoS8us0yMDn", "fi/TWFo25GXbCf0SieeeIY803KHnGwMuzCTpHEqSeWqYGcivJGxd6D0/5uX3vSesaQLHVplBZ/K/G4merKw", "dtusmqC3CUjk0TgCGZxGDQ3AaPafUf3/ef1ktkmnS9qQ7DRCz2rwIgLmoNp2Qb9n6/fwLvCMBJ3FCVCXl1m", "2WCwYAGMRlA2gvhKU+6i/QuVXA8QPLnL5FyM+yE/4hE8yyi+Yu35J9MpYJQwjx2K7j7E0XNdBrwB+sE8Esn", "qP18tZXlRG/EJsM8tUwN5FaSN2IkWQKsOkmIRWeJxqFVIuob9pzJ6Tn5VZLWNYBiq02hzEcgjyrHlh6y+F+", "Nxc9WV+xpSoKNo43oZUnjywYxORw72PbETl3ioxybJgBDMonBQgozDwteUn7LKppGgMzmipW7j0nIoD01ha", "w6z5sSME7bPS/A037r8VIdholY7F8FDIyThhCAhLorz0NCHe/v2HVeVk1VgzRn/H7/BN4RgJOi7+oLln1bL", "LihKhPy6jbL5jA/HLqG7XRvEJZVMRRZgDGBg1p5eII/FsJTnnQX6V1IU0aRPHsy4sFz79i36YYWn+L61/+F", "XamP9U9RrDdQ0tFkWl7kW4ttWETzF2/JP5kG1eYYJ6XkJiGWNtwqyo9Efwcj02KmVPv2J4qa6TTgD6i2n5W", "hWDuw1gngl05Q+/mImPWYBjwgRgG4XNGNrpSyXylJ3sXCTw14apkayK0kbyb7jBWAwf/Qr9slXAtTSyTxSj", "BTQz+Qm+FdhdUQjZ3gv8yQ2ljhRl827DmT03Pyq2h9LJybHykUTz78WJZwQnYRr+lX3hyZyZiPQB5Vji09x", "h5VER3i9oJk8b8ai5+trjpgqhXD83YRs0ADXEhhwuXt0RZTAA0ZWsqSxpcNYnI4lAPTmEUOqYcdI3rRzpwd", "c0Oyb96G8MbMU6XaWNVCy7cNNM9XnS4QCIQUZh4WvKT82oVzEV7Qf0P9xqPVU78UIaNXttob08+eKncfk5B", "Be2p05gqc2C2g1QpZdZ43JWCcVMhgkX9JuyPd6MnY9NsP14N53Ne8t9RopDoME7HYvwr6qxkc+bRktXOLsF", "VyJtBBLRqlWjpKC/49DRDcafgGhWOcBdMhlN066rysmqoGac60LbmV4mqycZNuaVHvBdkTzf98XqdpAqxE3", "9UXLPu2WBpOwBhkl23nG9DCfrfztKJFQddx/59vHcxhfjh0DdvpkvBrNzxhAFa1s7vzMQ5rNOsirvx5YrCL", "YgIHtfLwBH88kxK6upzfwCyEpzzpLtK7chWyM6FCCQT7NRt6KtC98KWkDnVivGZPgufesW/TDS3cdsu+J7/", "WklVWYvesLWJmC8d3+ORBudl1eAj6C0l5kCvpHfVDJaIvosm0vMi3Ftv8WKGzgNvNZNsbcXeNtKYGhYpkeM", "XYfbkMqs0xTkrJTVI72D4GJhLyQixtuFWUH4kcvXi3HfjENpWd0f6WanDCywzE8d4Gq33sTxQ102nAH7LeA", "TqbBRugO/6ocxCXr1Rlb718WPt068eAV3fOhi/HmRFCeIbq9HgQMesxDXhAjE6g/j5FFJszaeMu+kh78FE3", "cjv1ABcr7r5SkryLhZ8a4MOHs8PpRKXw1DI1kFtJ3q5FJzrYN5JhJ2WOc1OlJpV59Jt8G8n9Kl63S7gWppZ", "IACZet17KTfeJBvf+1Vj5A9eX4vGdNCK8qSid83I84vX3uYj8OlA5Sn6ZIbWxwo2+IAg0uvmuVgEHS+R+9M", "E9Y1na8XG8rebc0PpYODc/UiiOa003f1OJl558+LEs4YTswO3tvmSNX1NJzUT37x/rpxdcUfinczAYMB+BP", "KocW3pujpQz4nCAxeeuPXpp4jQxuT8odSGO746jcehtRRmCaf3g/WINdVnWdMBUK4bn7SIqUUEkzos2nQ0S", "keDD5F3/U4OE74uIhkDaoy2mABoytIQyOKlIdukLlCWNLxvE5HDKtJggU6g/z0OUMWnYOos7HQUkZpBWUIQ", "6RvSinTk75mTX4a3VVeBZ7fdI5F7HVK2zZl3rFquPEs3ZIun5o09bk0g35rHPlOQaaJ6vOl0gEET5i6ByMf", "uvY7pbZH9ekM09K05rNzJLcrQL5yK8oP+G6pryLfTMJDn6jUerp34pQqQcUqTvEvL9LTz77WSARglzre7iL", "OydtlTuPiYhg/bUCn8rKWnvLWuDX4Jg4n2Zn93Ol2+qEUIgfyF9ZDxsGQwhsGhrdADCs6iQwSL/knZH9gHU", "Lbf+rfjRQgTpupHGmo/TEeby/R0lBvO4r3lvqdFYYq2gMQNybkh1GCZisX8VFuQNKSrdpKqfxKRgoU8QXsF", "VsW/pI8vh5hZhq+RMoIO4h3SkrCB7PDGn3e0nss/IbzbI4m/eFHcRibfggNbUPk8You/Iug+BxjgLpkMou3", "WYqR6pC0Rgyr/qzm0GKwuo4XvbYk5H0BdoW3IrxdVk4zbKZySNub9cJt3Sot4Lsid4TMetlmdpmPFsbuQd9", "d1sr/1761WZBtOIvqsvWPZtsdYvviAQmrYOXw8XaZsIAvoBngJm02TZRQAAAAAAAAAAdw3hKr0Wpj7uGsJV", "ei1MfZkXI3/HO+pD3DWEq/RamPqrOGWBSUw+xDIvRv6Od9SHRSKn1DNhcrnT+J8PupPpwaT1fiUHhU//PeJ", "dWsC+pbxK77xwfagDgg/NG6ROyXE7eMD6jvPf1wXh19nxNOQ9RpbaONuJ8pt4zWKoRycBCre6b0ltmhesiS", "N4ahJdLEbKVHWLOOA64PQRVyzs01uSTWZazcZuTTRz/03uual23jCIQA+TFGB4Dh6aN0idkuN2aZfWYiCER", "UjwgPUd57+vC4eNFDdaqQk1wq+z42nIe4y1olLJ1N7dsiy1cbYT5TfxW7iQnK7zkc/xVsfXHSTNWoZbJv2g", "MmtkH0wFgmcJgSdoQeSo2h8nGS1jQ3zpflWgWm6iVlRo857DeYEpk1MZ3bR0YAMuRb/jIq5Y2Ke3JJtVo7n", "yGqGCpcy0mo3dmmjmu7l7p2CMztj+m9xzU+28YYmWPVnu+xpfEIEeJinA8BxnjP8MlNZWIjw0b5A6JcftSz", "mOuoczYdPSLq3FQAiLkKUjTO/9Hi2u4AHrO85/XxeXDAoRc2n5KQ4bKW60UhNqeRbIRAlEtVTvzPCfgLYuL", "JjBEbU9oIgSAdYyyvqbYlF229PgR43EbzP5dDR07LbWRPSVHsn6EOjd47ZhDsH6q6ruV0uz11yV4q2OrztI", "mrWVoG+Fhl48iwy3TPpBZdbIe7qt0PxzcPY+mAoEzxICT0mV6y5yBKRx0ILIUbU/TjKnjyl7CCnoDDFVEaC", "B23N0RljwijzN1UrfT9P1+/Y/CahCMt9G4Jk37WCVC3WB646abXQhyJdNsAN6V14PrKfzdHe2dLK6Ac0vzy", "boHEmQAljCx8KhXzY8wdXkvWZk3H+22AWX23J6QfP6okPoEwj4hPdDaVUFrsYd4GAWkj5EhWrtgTwvKOK7/", "De556baecOLOljNG8zf/RIte7Lc9zW+ZSCamGHhk4AgAj1MUoDhOVcP3GbvlkcHzhj/GSitrUS5FR4zlbsL", "ehP7SXgmbFfvZPaoUpt68dH94YstXEEbkorsagfhV72sz87N09I2zxW4wyz5byBpKyHUD4aoG4NoVtnurBU", "NJVbAA9Z3nP++LrcON10h6RgQLhkUIubS8lNZFPUIW8RUbRw2UtxopSbUazuz9tWzgOryLJCJEohqqYUhca", "OvnsyX3pnhPwFtXViplAAVvHv7ZjCDI2p7QBElR47CQMZWtxsCrGWU9TfFonWhhL5IIWOc7LanwY8aid+bu", "0brMgwv4Q1hfjC7/rSZemyfGgboEqfje7xlwdP45JR2XU98xV7a0VT6m0+kLGOmWRux8rKKXT9OOM41iWAe", "SEPZ5IifxiCvyIoHJLbtX9jFay2ZoEthQdJIUl6boSI236l4440HHHP9DqzQ7HWlBPDvhm3605ud58z5qsE", "52OrqLdMX15/mfDAVCJ4lBJ4LPfQiIzOioJIq113kCEjj5Sc2d1ke7t2gBZGjan+cZNcIcInXaTpaTh9T9h", "BS0Bk5ErLcrUR2J2KqIkADt+foFafDar6hQdaMsOAVeZqrlfu9AT/EjA2rvp+m6/ftfxLJkkfBSvvZLFCFZ", "L6NwDNvJ4iFlDDWlVGxUr1PuSQOKcZfXGUEMqgXX0h/GsMJQlQoRZ4wfh/kam1nOeRNfpbTGmrYzvBoMO2D", "ffuxN1ParvRwGpuKRXyQXp5N0DmSIAUpk6z6hISGO7CEj4VDv2x4x4lur/6pykaCq8l7zci4//WmKFFw3h7", "BbLELLrfl9IIbvOoECvNSvI1m0t+DAcnE+msz9T4Xb/pjfBCK+SyFuRRx8aBEOiOHUVNWdHdbUT4mXrdeyk", "33AL9JlCENdh1DyER1C7Bgu32T/OWXHpMqsuTxBL2jhYyMfeYnwmS+Zs8K68bo2ajA8U/JYTzqybJIOMSAF", "lffFHah06NpkOT+NdbeQkMt8lgLQAR6mKQAw3M3CZuyGRZlTa4euM3eLY8O2RNZ52M7KTCcMf4zUFpbies8", "HxntTP23cis8Zip3F/QFJt1Ml2Gxyk1lBKgf/nfqOmjlgqLo0dSjf8b9ZdM7l9RyJ9fYxZ2pkVCAA+uk7xD", "mXWEpVrJJLn9KQlaRiaNtCEejfCyfBVOenZunpW2eK+mQeo0YezgVcIdZ8t9A0lYHirjYYlZ0aEKoHwxRNw", "bRNaX+JuwhoO+sst1ZKxpKrNu/PHOWDOySgAes7zj/fV33Ck3FhenbY24dbrpC0jEgGRCPkP/Elx5cMihEz", "KXlpys/yW5xs0OZsijqEbaIqdrFJQs7C54P5FP/M+CCbJScJPLSyj96MqK95fG1+EHY4croEJ9FV37fj8q3", "S3Y2DGb4x1ZhyyCqWGHQdR4MG0AbFt2UNLEN5iW8M8N/Atq6sMs+IlW/zByOUikBKnj39s0lJOAAxeFQ82A", "GR9T2gCJKFwum/kuWhHSOHIWBjK1uN/kRZKsxu8gJb8tccLhJU3EYxr1aBV/1T4HRniXCZB8M9tx/D39yuT", "Kz/tjbTBPLi8TzOfHxBW21XeQajjY+h/Yq6fukiyghyHFRazgl27AHBlyKEpjNFjmfS6ltX/b8euhGSEfi4", "FpErWTvk9GBKP3aaQ65bJeOw0N+LcarrGSANHPM7Ba6wr6iqfQ3n0hZxtWkFR0iXv/4TLM2YuVlFbs7vtdI", "WHOzhX6ccJxrEsE8CZGRttYEZwKQhrLJET+NQeeLU+OsKSt/AAAAAAAAAADlUZmWzImUFsqjMi2ZEyktL/K", "ru1WavTuUR2VaMidSWnEW/Mz+rsZMXuRXd6s0e3e7tc7hZ73vYSiPyrRkTqS0zd5TIqjHMKLiLPiZ/V2NmQ", "d9YQ8x1BmPvMiv7lZp9u5ZmTZ4muBi+HZrncPPet/DkzoEVQPzS9U7jQIxmrqRXd7cm6dWMwVL8S4wHAOpu", "HAUf6mKzyAsZq/KZ2uoncMHSpv+/WQUVxFlaVVGMY7qKoA4zND9B348EwLIhf70Nen2U1ETMn2h/9mh+qhn", "5xzEPPBjPqtuiNKHRa3fzNNns2IUNEkAWvOlTeaf8lXATp6otwZkmUnaiHYaBWI0dSO7k0uc9Pj8t628uTd", "PrWYKllnortlh756A4l1gOAZSceEHDPmuytvl9yj+UhWfQVjMza/Lg1PIzNpelc/WUDuHD7vEVkCcshMZlD", "b9+8koriJxZ2RtBaE6NMrSqoxiHNVVL4MzGq6VQUMAcZih+w/8eOUgATc3hmhuTZcHU67Psuaoxp7FYkYm8", "Ic0NX433JvLYmWs6PtVD93Z0GIJnOjgvDyB+59QYXSqE3NQJAX7yZH2IsmyyXJdh2UYzefKgRZSgElUcQYI", "gkSvu//KU5I/f0rqZlyfG6tp8V+ovfimRAgUDjErNC/QHjv8mpBhtW0l3q0DBq08+TOHp52cO8yfQmL2BAr", "3RQtUTQSvsaLftm+oVTYnblYieRPg+MYJ680Y9rFhUMViWQ7ZQ8rrkPjkNTwSU31ccXAjryhXKF+CO/ZKec", "6+kwuv4GWLZQXGkRLbgNr8kwoYhs07bzJybaVprN4+q+ShLP268cwAX/S2QIEUnZnJOD/Ul7wqn62hdg4fW", "XsGO23/mgl2ia2AOGUnMpPYNBb07LMkKG3695NRXEXNPGNhX9jIU+LOyNoKQnVoB59RTMbL4X6UpVUZxTiq", "q3H0zI8JsT69XgZnNFwrg4a7V/6ikKIXkADiMEP3H/jx5bOp1TuWbOfKQQJubgzR3C8Qm/iihUXK8b2Y/g+", "5vPkU7AFowzAo7zseqtOWqpXU3k8zRVojAcJl+v2kPZ7uo4CrZDLxF3q1r1nPiaSNx45KCFYfaARTmNkyUk", "pr9xhNPGPL3Kd+jFsTkWBn8uQxYPbA+fE+baV2TXU3EFnQSheoJK6GlVneAYfWBT3Aw2M6YoecqwxK9yzKM", "JrPlQMtpC9hA1lZirmyAJOo4gwQBInlwjF0wJmQn153/5WnJH/+uyZmA2ut6+iU1M24PjdW03GFVC7yvsLF", "4r9Qe/FNiRAH7sntPcQdBigcYlZoXqA9zU37wKTXNCt2+DUhw2rbSpOprLcP409cvFsHDFp58mdZCp6alvB", "mcQ5POzl3mD+F6x6ir7sRq5PE7AkU7osWqCG9kIIiAoK+mgheY0W/bd9/Wcf1iTb5yVCrbE7crETytfr12B", "Al0OQmwPGNE9abMcORaBvfXw8n7GPDoIrFshwJMlo2RkwmCrKHlNch8clrV9YNQe14XX14JKb6uOLgRp11P", "2x0a3RQNcI5CO0irtjQk6CeIas6zv9hCyV0MYf1GjCSs7i4E+OhhVxS3wX8gkTUxcQTjGiUayZuf0YW1a+O", "d/fpip9BuR1N87yJbAps+BxqKkXlnnrX7sGREH8jQTK/WAfc9rdXiQqW5rtLWDZsWw9wd8LMIEOppMsiWHE", "bpvg9Xe7R5Q14VT5bQ+0cPp0Ep82PZIgosvYMdtr+NRNXp5XgFnehBewSWwFxyk5kCUPCl71D2nImsWks6N", "lnScPg8LokUPNfUNr07yejuIq1i2156yosnJp5xsK+sJGnfyhfVHI5BbHEnZG1FYTq0CHMCCPZDX7GDj6jm", "IyXw/3rbzoOQB5X60PYPGrZV41jpoml/BXeGXWJew5HQESkTmwql9GMzTBY159ZMOtw3zkyzsCmJ/lLLx08", "ax1yY/YU+G3yi77qYgJrV/bevRkp144Gb0hxkL3BofTE8yQKAPpEpV1l6IOU7P8Qk4SPPnuNGkEKEkO375s", "1s6GpFi1SoNDiOD/apMa2ieimpUxUoMdsuT8zgN000UNLlIjVR4nqphoNHhnOHfwdr8P/fnPynfj+Wmmy+m", "aL1wzx0udg27AyXWhEK+lPpqFnbBEoGgRzRDb1h+STkGVrxF48sQktXo6Vx6p9gLlINSAJSxo9VinQcZDd1", "rTCP/+DO2aDLn8EGtKi8E+n6xKyZaSU1u4xmlc0PQIaZ6WMeMaWuU/9GLedlw8vg3SMoSYiwc7kyWPAw3NY", "WChA99bsgfPjfdpK7QnQanWxU977mupuILKglS5/u/e2fikBOFBJXA0rs7wDtRjFm+c6KBUOrQt6gIfHdOv", "8kuxMDlNixA45VxmU7lkhX6DB1R16T//yo8d4IYN8GqM6UbSoF2o1UZHq4TKqUdAACHwtuz5Ha7XGnUoG0S", "aO5F8Lho9FMKEW9LDTFfgLREdtJh+cbB3XfWlzHG8nyDIs8OXQ5rPeHd5bXoV8DuX4j8LISfWa80M6DCkuS", "HWSpmuVv+LB4YSJmT4Et1tcv2zIp5J70sipxH+h9uKbEiEhLjhgLhKGNw7ck9t7iDsM640KTbcBrxpQOMSs", "0LxAe7VpXTocNdRtmpv2gUmvaVZ/ym8XhSb9QOzwa0KG1baVCaHy1EpcIoMmU1lvH8afuMMCwPnTTwuueLc", "OGLTy5M+d5peOeHtw2bIUPDUt4c3iV0Wlo+FoWfQAAAAAAAAAAH+du6PRNu0K/jp3R6Nt2hWBp8zkcls3H/", "x17o5G27Qrg+hVLZftWSECT5nJ5bZuPn3SImo0gIM0+OvcHY22aVeHdme+XICEXQbRq1ou27NCeUwQ+f/tX", "kgEnjKTy23dfHsDiTAaWzB2+qRF1GgAB2mFOf53uTbqY/DXuTsabdOuj0oCmMtbPqQO7c58uQAJu3Fwdd9o", "NuSxDKJXtVy2Z4VzP+wWjYCKj/KYIPL/272QjQWbUS7tUJoIPGUml9u6+Xeh3oVG7Vfz9gYSYTS2YOyJm6n", "C5YCN5vRJi6jRAA7Si9QwCwA249gKc/zvcm3Ux3XuR0yjWznNizzkL2f8f2n0oV+MtsqSY3UGk2jEkaV8Cp", "soyxWnSHZ3SQqhISfLQgjUsQLwESZIiXN95oJKEVf27sZFU3z8XXPXODLqShY+DEqDkTt8+zSN7U91SSfMK", "/Jw9NaYESEhj6LWvKyRohXwP20ffadPH3GYofsP/HgADgUaWN7KlQp7610UfZGsxwR25resp0HNhdEqU978", "dtL6TJHwD8qb2Iees5o7Shjs+AMIOep89eZ5pMTdmCfC+QY5f35JES/zgwCBCfAnxZD8nTqqIREomn069k5", "TSh+FAqdN7YJ88o9/dW+HtvxxuwDo1CRnypyxgU8YwBWRq67+0qNjxKdGpBZ5yF/O+P/SaeRz/B/OEtjoQ7", "8YbZUlx5feBLu8o8jN6gwm0YgjS/mVkZ1yWRWm8xQ2UZYrTpHsa6vqNfp4fObukhRCQ06WhZEPr+GSeHuPE", "KhjBeAjTJBvNdimMRWhmhLn+swFlSKubXpBb9Sjz6Ts3Y2Lpvj4u5NANih3zhWx5q5xZNSVLHyZM8rHBaPB", "dhiUBiN3+PZpZwm9gKbOG2Ma25/qkk6YV2VGJElDeHVd5OHorTEjQkKbfFMO4BWvSB5FrXlZI0UrYdgW2og", "VqCHgf9o++k6fPp/iYZ0reHI04jBD9x/48QCdrfhUzs4cChwKNLC8lSsVY5ePE22jxh+dRSxwqQSAu+LYl9", "N4Mm2xY39bNwppWq4c4uCU21+3pGEwwv7v3zSQHq15XT7p2ZqfCrW5TLLuheCXDhqdhAOPZa7wbSSy6ewaM", "0vO9YQE5puUhyqH3zP55Ak8iVbp3vOZ2x7jYmldx+ZGpUCzX7DNZ+FppMEEh9IYfNIHEDJq2G2SlUuzaVMV", "Eg8u6GJfvh+TqOIMEASJAOw1Wa/BMmQKked7xfWy5z7uesBmJIQKNG/dDIJW3z0rEEC3IYfp0CGVeUlWPt8", "6Qurk8vXv6ddIa0M+EZ2y4FcU3oWyTIQNXWkMp9h4BI5pFpEce6kyY2OXNtCf22lUfOirazwKX7l2R2EH58", "/XJpE4/LxEHuHLm7lbcKBsuvyExsbLA72MEY67FOlpiQySusSJUspYOn+wRS6eLiphSK86syWN+1elpb+K2", "/pCYU/GwBdgWZNXosxBsKy94QyV0z4tFx4wOnjZQ/81dAS6++08Yo7X1YwW573FQjOn1yH4wlj5kHbhzPK3", "tr7c1br1P8grBX8EjBg1SYzJm3bXLyo2EXI4p+HCIEvDUFKTYUEUNF7r8UJXrB61+ScVMAybAcpknLbhOnY", "LT11iwVgMnGgwwNliiTpxYrFnFYb7YUZ9zvquJSpXq3ezKIxPHtcoQ8y1N+zP4cVJTRL7CL268lYyj0CrbI", "wfXMxd48ioK1n4s8BYa3kdtPIyZ5SPC0aD7U36LyzacG7nMCgNRu7w7dNPtbblP8YA2c4SegFNnTfGsY/Bo", "pyr2sw0tj/VJZ0wr0srhHb0q92lyoxIkobw6rq1EfMxV8YHsMjD0VtjRoSEt15q+LJwaY42+aYcwCtekUlk", "Hb8RHbObPIpa87JGilZDF+FQY3BnXMKwLbQRK1BDvS2WF8AdvUnA/7R99J0+fb9iD94lq9N3PsXDOlfw5Gh", "BWHiZhsYJYsRhhu4/8OMBu/w9Te7GDgs6W/GpnJ05FEXGSgpNq9QeOBRoYHkrVypHidPDqB26IMYuHyfaRo", "0/ubOkhAtwYDVRGM+4AS/ZQy6FdBvQGTRJryK4/6JCA1bQvwNcc3TuXK1tITZH9G1o0vCalZbCgGJTV1Zx5", "Jm3fSzK7dI1r1p3qfMTpYyZsBTWbqgGXa9dHlfJZOIv9GoBKFTfQf7ChwtVhv0rykIEPyobRogbdOk1q7yK", "bGkv3irUITHPuBkzIKHPdoMbQgrt3lLNIMp05+df9QHEuC/Q+CBoumdpGT3yXbqYDV2ZvsYiJyOujK9TzKO", "A70r+9GTT3B1U6S/CidlZJKqelvRjuia5ET1Hwo6wpx7d2TWZua/Yg2Z65K9UpaVRRBDQL9eR2sz/swEZOp", "tbazNXc0INhCT2iPSidOCO2iQrl2bTpiqluZA0t+VLICQeXNDFvnw/W4PncxSIkTUmUcUZIAgSAVnMfrrxP", "v8L2GuyXoNlyBSn9gn9UlMlHiLP94rrZc99XVJMKTpTInfc9YDNSAgVaKNoO26ZPvhi3roZBK2+e1ahJ6Kn", "fIiWXCCAbkMO06FDXx3V4N/lTEkq85KsfL51hFVuKQ+tiJiO1Mnl69/Tr5GrVF5IDuVCm9aGfCI6ZcGvqRv", "HgetTLKUovAtlmQgbulchsMZIPvaw0hhOsfEIHNOthfUSID7x2SwiOfZSZcbGU7+CVYNTK8wubaA/t9Oo+F", "HwG5xm5UXy0FfXeBS+cu2vymzbxYif5wAAAAAAAAAAAPUEklguvLBreZ584nqhVWuMmu66VB3l1vI8+cT1Q", "qvWBzhrnNv+G72LooUmj+P+vX6mF36hX07Hdu6q2s1cYseD6jiC4+DSrA9w1ji3/Tes+nREYJlBhxGE0lMe", "OB7JEXHWwUYWonl6/Uwv/EK/nHoISL2kbAMsju3cVbWbucSOGNjH7bUFdOWUQilX4RiR5WFGuw/PpCFYH+C", "scW77b1jq5D4pQEffM2Z+0JMUWjozk3pCyzrmikmbMv9vVuWmSW42bTd4WRYi4qyDjSxE8yIXqBHVAvhDn2", "kOBqujpw2fnAqU840bvfQQkHpJ2QZY9OWU6BH3uuh3SC7zORGqvXe9KmFhPxYNHDGwj9trC+gcxLQdg0W3W", "KG6Egr95OgWoU8WmKXKVKbKw4x2H55JQ8o2iORHsPXzsD7AWePc9t+wy8TLu/JKb9tHXiUBpleK27Jat1mI", "6zpmzPygJym0dGY5+DJ/BwjEDbVi3MVTFSENQGZOnX2pkfml8qaMihN5+VD2NNSkr8mS3GzabvCyLJIpaEg", "23g6cL1fOX0h/UdIvosrNEFHtYkQuUCOqBfCHRNtUsfIrTDc+0xwMVkdPGz4mGJ4OafOrVaqCcLQ97k5VX4", "bi7BNS/ughIPWSsg2w6NQkZ8qcsQCDWL6JcMis5YOtuhso5hBVhQPLviAEjU+F9s8seCox/+56VcLCfiwa7", "o9RUJpQkKpT8fdH5PHP5FME89W833NUOIhpOwaLbrE4fW2pXqXSAUJ1JRT6ydEtQoAhhqLnbZ0pDLtoGLNw", "eCn5v/pAnczIlIcZ7T48k4aUch1/ZhIvNv/+h5HcRjLT/wuDA4RojmML7hfrlZ80iwsbE3nNsYg7YJeJl3f", "lld5gYo0FL8spbt0cKxJRanYg3ekvgAlEypC2ZbVusxDXdbaQsfzrPmvFzJj5QU9SaOnMbf3TF3zUWafhZz", "2tKMm8pxRjr/UGdQwaasW4i6cqQhqfwSrTiZbycRNbxGndixdx5l9WMfM3p/JL5U0ZFSfy8r7h30E7m0KZM", "nsx+2+Gp5nHf6OjQToXJLnZtN3gZVkkTN0mhc7Z6U/AR8g/msQMTzVDWme0eLw1PQvnw9h7kDXID3Wb9scg", "XkSVmyGi2sVesZEJeYxmdePPNx4HLTk74zozjF8DhYuItqli5VeYbohDrfC9eSTefKY5GKyOnjZ8Uz2K9KA", "ihhffp2RO9D9jFyqj9hbag9OqVAXhaHvcnaqhAXMwVWAtwS2bnYoBfcjB2J8P0i/BeLvQ17J2Q8JUuyXTIC", "5tfuTQqUnOlDljAdBcTVzMF9+xbSLrS7K2gP9t1+/Z6pg8TwZbdTdQzCGqBq5xpQjinRoKB5Z9QQganwryk", "u8ZJqYvYX4IAaNyu8phiwyT+1wHetz1qoSF/Vg03ACuFt3T5IS3jDT4Z4f5Ybd5MGo/qUXRzXF415vFRv3N", "hHxFw+v6TaYI5qt5v+eopv3iOSGRWxgbg0QuXzAEVht2QLwHHrjmcPraUr1KpQNwD97A5WQZs4TqSij0k6N", "bhB9Ouqy9H+vvk9RUFukCDu9m0MZOx76+Uhh20TBm4fBS7XJDaEhdQDlh6K3SHEClOZTsP4oy/BVDnKSCLl", "7/OUNpoBB2cEOJKOU6/swkXmwoED5slAri3JVumHvqq72SlZuc6bKFASL+FwYHCNEcx/7iApVQ/6B3fU+4j", "ngZsCJ9urwcIDcMkhY2JvKaYxF3FsMiYMJNrcervYR3vOzyiatIgOXkwk45wMQaC16WU9zAMR6ZBrjvbLo5", "ViSi1OxAusxStvr6UPDRQMhYQK5NFdG1zMoYgPGlbMtq3WYhrutsPm5PPg8SWwey9KGEWw++B0fwM9x1sw7", "zomTbzYIJ5vNXYEmVrLVWmNv6py/4qLOYLv41d9YUAyVQWCIJd0tNJaVcsFFZ9/1OKcZe6w3qGE7cwsyzI1", "aoNNSKcRdPVYQ0IY7jT2HpNF+tFA31NfTRX1gQn60bSGHiJraI07oXL+LTshqLlKufiV8o9DHAtnqJqixma", "e4Kyo8EXcNhDJfQj/FZUTkiK2DkfcO/g3Y2heSIxy3bWIo1WfZhOqX51XtZA2Wo/ddpyzKP/0ZHg3QuMnr7", "1B+tyJ5IcrNpu8HLskiHt/vj73cCIwstFVm7aucj/imHAZXWV56Aj5B/NIkZnnWLAicaNan1+RHsnU4oTPU", "MFX7FYJT8AemBltSXLhQBHIUEjLmSpGqQH+o27Y9BamUbeG7DM/HXG71vEGJsv9fuuf1ITNAPvGIjE/IYze", "q8lyeBqjZxWsafbzwOWnJ2xmprrlZ0zsat5vFA7CDTI60T9dK0Dm+TEG1TxcqvMN0QmFdXkoGMbXsUzbko1", "ZGIe+HJK3D7LTj4THMwWB09bfi5d6IAM4HdkzXtTLpnnDiTwOne4kkgiC6+T8mc6H/GLktLW8TGw3ZFx9G1", "fpLek0Uy1ScmvGIjPzqdmoLQYQ8/z5kI2v7dv1RDA+ZgqsBaVLYHdDiEfOrpyKFjRiUjpOk9pfEeC58UgrE", "/H6RfgvGCRDuN/HE+QXahr2XthoSpdlSr97WoOBkd2DEZD/wl/B0tNYtX0plMoFOTnClzxgKgppcOcV16ss", "sqDeDLCWdXy98JcpMn2+ex10HPN0vYy7EiRV1vZWR72q7fs9UxeZ7aW9shjR/FLmclfTbzvppgZ9B5pKuQJ", "tAMXONKEcQ7NQyp59hJ6oeFAAAAAAAAAAB5iTUwyPBuf/ISa2CQ4d3+i5teUFgRs4GPtkGYc+ViyfY/dKi7", "FQy2faQq+OMEvzcELR/IK/TRSHX+FGi07BymDHchWHwcctmH7H8IJA3BWP5lSjjs/a8n+khV8McJfm+DwWD", "AD/kQEAhaPpBX6KORcdMLoJ8Yze6Bb76IO//gePjmi7jzD44Hc33V6KsePYYK9ODYY+5T+Q7Z/xBIGoKxd1", "DKIIDq7M78y5Rw2PtfT4VCoUAQCzEw9JGq4I8T/N6NGJ/QR+OSoQaDwYAf8iEgfwr0sNcCT197J+t4/PaeF", "wKu3kg0BvBoiTWAGGwXQ+nwvLUopOctlgLffBF3/sHxe1ZJIb8Or47wzRdx5x8cD4lEIkEv73JwjWk9iQQb", "ozj04Ai5zOvNR397VumU+n7GBvJj2VwKELl3IWh5wxLdVw6oXUkL4rMohTMDGVPzAKn8ujYpmwNu1viXKeG", "w97+egR4c0XgH0eEKhUKBIBZiYHMMd7Ho5gwfg7DCmUwBIYn6OfephPFP9nGiqfnc4Px3CCucyRQQkggMBo", "MBP+RDQHWPtjH3FC0//hToYa8Fnr6Hnd1RZ/XwwfZO1vH47T0vj8fjwTAdU1AEXL2RaAzg0X3ViKGg/I6ue", "fiXaYsIX+YAcaJZQ/gxmYvq/Akb6YIY8mPJOdMZ7GdvLW56vdpa1xakW0p1KjSonT8FGi07hynktjAq5cvp", "VuCbL+LOPzgemRIa0gbPVmESiUSCXt7l4GsAcbKWLoufGtN6Egk2RnFjWk8iwcYoDujBEXKZ15uPkUgkQlE", "n9fCVZTuKetMkuOzsDrqyI0rHZ3dQ6uoy+UYe/mXaIsKXOe5C0PKGJbqvl8vlwk7V1NAcULuSFsRnUWXZjq", "LeNAkuYfSRavXA2GYYfaRaPTC2GZPm+gplIQWY6m/POq3Ra+ebvMSaMsmmCeI18ar6Och2aa6v+qIoe/cQJ", "5rKatgViBQKhQJBLMTAbYOwMoncqr/mGO5i0c0ZPp+R21IZPXdBbfISa8okmyYUeydbAtT1WZ/geQtaxUbY", "5mlMO5I1KKfiRFPzucH575vNZsNxMZeQEFY4kykgJBFp3w2j4dBKbhgMBgN+yIeAYYUzM7Y46f/qHm1j7il", "afpOXWFMm2TQBl7pHmw0t5UnuM3Krxd2LNmWoLPudzDi3HCEZy1U8Vsjsnazj8dt7XpUUmdM5KxUhHo/Hg2", "E6pqBnBvKzqcrI32Mr7XuCPhmXGqLYS0rOd+iROYYbEt/EaeiwsyvaL6oWmWO4i0U3Z/jg6o27jccJh2tx0", "+vV1roGEvjm2x0m1HkW1fkTNtIFMW9czCP+ImtO5MeSc6Yz2M+dTqdDbsO2sLXJS6wpk2yazEB+nOFjAuVH", "2yDMuXKxZD5SFfxxgt8bOn8KNFp2DlND9j8EkoZgLMhtYVTKl9OtseRUZAJnvdLAN1/EnX9wPLm+avRVjx5", "DMiU0pA2ercJLrAGUxW7DvU+BHlzumhL1NggrbCZqfIq9k3U8fnvPC8QaQAy2i6F0NKb1JBJsjOJNL8AU2p", "zinca0nkSCjVEcvz2rdEp9P2O7ELS8YYnuK8KZgYypeYBUSQLf3PFoM9Uwi+rsOZhdqkFY4UymgJBEONHUf", "G5w/juzSoosNmFNusrDvxz+kSPFzu6g1NVl8o23Z5XkHZWc8jz8y7RFhC9zRXX+hI10QQy3Fje9Xm2ta86f", "Ao2WncMURQRc3c6McJU8jWntBnwe6jigdiUtiM+iQSlDFeV4od3Ksh1FvWkSXLM7KHV1mXwjwugj1eqBsc2", "7YRblInHfsjD6SLV6YGwzSXN9hbKQAkxNXmJNmWTTBDTXV31RlL17v0wJLQmFDvrGxTwdwXVghTZ5iTVlkk", "0TT/C8Ba1iI2zEa+JV9XOQ7b3i12U9g/6Suc/IrRZ3L9rARv2d3odBpUvdo82GlvIkMlSW/U5mnFtDh51d0", "X5RtToOqG0Zjj/KsZX2PUGfjEvIHMMNiW/iNMwx3MWimzN8tbjp9WprXQM+I7elMnrugkeqgpX6ioD92uQl", "1pRJNk2jbRDmXLlYMij2TrYEqOuzUX97hsxYhcxVUmRO56xUhCzbUX4vXDr7p0APLndNiXreyToev73nBa8", "aMb4gpSrr1pMEjuhVRJRdCFresET3FSSBb+54tJlqIKxwJlNASCJZJUUWm7AmXdK+G0bDoZXcqzcudgtR+6", "Nbi5ter7bWNSICrm5nRrhKqZnwPj9XC8vQEMUO96dltNQ92sbcU7T8rbTv9hSj2oMmL7GmTLJpAl+mhJaEQ", "gd9LnWPNhtaypNX/LoG06qk7Nxn5FaLuxdtpe7RZkNLeRKhw86uaL+oWthK+56gT8YlU9GlzvhedaQqWJD+", "MK4b29g7Wcfjt/e8obJs9ytHmcMqKTKnc1YqQlOgB5e7pkQ9V40YX5BSlXUuBC1vWKL7CqWfcz8As0iL3BZ", "GD8hDJvStxU2vV1vrGtRMeJ+fq4VlX9cmz8e6NuQmXhP/D0pYmyJzDDckvonTW/o5B+xO56zQYWdXtF9ULa", "noUmd8rzpSWVTnT9hIF8Qg3dJ/ELh5u6tGjC9Iqco60s+5H4BZpEXW4qbXq611Da9rk+djXRtyJPDNtztMq", "PNdefiH87zGjCyq8ydspAtiVSPGF6RUZR3euJhH/EXWnKcxrXc0tbjjoxyyvx9BaavalYeP17EH1FEO2d+P", "oLRVKIfs70dQ2ioAQYCQwQILnAEgS1AAAAAAAAUAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAIAAAADAAAAEEtQAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhIUAAAQZyRwQILFCRpb", "nRBcnJheUZyb21TdHJpbmcAAEGwkcECC2Ioc2l6ZV90IGlkeCwgc2l6ZV90IHNpemUpPDo6PnsgdGhyb3cg", "J0FycmF5IGluZGV4ICcgKyBpZHggKyAnIG91dCBvZiBib3VuZHM6IFswLCcgKyBzaXplICsgJyknOyB9AA==" ].join(""); function _base64ToArrayBuffer(base64) { var binary_string = window.atob(base64); var len = binary_string.length; var bytes = new Uint8Array(len); for (var i = 0; i < len; i++) { bytes[i] = binary_string.charCodeAt(i); } return bytes; } function getBinary(file) { if (typeof Buffer == "function"){ return Buffer.from(binaryInString, "base64"); } else { return _base64ToArrayBuffer(binaryInString); } } function getBinaryPromise() { // If we don't have the binary yet, try to to load it asynchronously. // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url. // See https://github.com/github/fetch/pull/92#issuecomment-140665932 // Cordova or Electron apps are typically loaded from a file:// url. // So use fetch if it is available and the url is not a file, otherwise fall back to XHR. // if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { // if (typeof fetch == 'function' // && !isFileURI(wasmBinaryFile) // ) { // return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) { // if (!response['ok']) { // throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; // } // return response['arrayBuffer'](); // }).catch(function () { // return getBinary(wasmBinaryFile); // }); // } // else { // if (readAsync) { // // fetch is not available or url is file => try XHR (readAsync uses XHR internally) // return new Promise(function(resolve, reject) { // readAsync(wasmBinaryFile, function(response) { resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))) }, reject) // }); // } // } // } // Otherwise, getBinary should be able to get it synchronously return Promise.resolve().then(function() { return getBinary(); }); } // Create the wasm instance. // Receives the wasm imports, returns the exports. function createWasm() { // prepare imports var info = { 'env': asmLibraryArg, 'wasi_snapshot_preview1': asmLibraryArg, }; // Load the wasm module and create an instance of using native support in the JS engine. // handle a generated wasm instance, receiving its exports and // performing other necessary setup /** @param {WebAssembly.Module=} module*/ function receiveInstance(instance, module) { var exports = instance.exports; Module['asm'] = exports; wasmMemory = Module['asm']['memory']; assert(wasmMemory, "memory not found in wasm exports"); // This assertion doesn't hold when emscripten is run in --post-link // mode. // TODO(sbc): Read INITIAL_MEMORY out of the wasm file in post-link mode. //assert(wasmMemory.buffer.byteLength === 16777216); updateGlobalBufferAndViews(wasmMemory.buffer); wasmTable = Module['asm']['__indirect_function_table']; assert(wasmTable, "table not found in wasm exports"); addOnInit(Module['asm']['__wasm_call_ctors']); removeRunDependency('wasm-instantiate'); } // we can't run yet (except in a pthread, where we have a custom sync instantiator) addRunDependency('wasm-instantiate'); // Prefer streaming instantiation if available. // Async compilation can be confusing when an error on the page overwrites Module // (for example, if the order of elements is wrong, and the one defining Module is // later), so we save Module and check it later. var trueModule = Module; function receiveInstantiationResult(result) { // 'result' is a ResultObject object which has both the module and instance. // receiveInstance() will swap in the exports (to Module.asm) so they can be called assert(Module === trueModule, 'the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?'); trueModule = null; // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line. // When the regression is fixed, can restore the above USE_PTHREADS-enabled path. receiveInstance(result['instance']); } function instantiateArrayBuffer(receiver) { return getBinaryPromise().then(function(binary) { return WebAssembly.instantiate(binary, info); }).then(function (instance) { return instance; }).then(receiver, function(reason) { err('failed to asynchronously prepare wasm: ' + reason); // Warn on some common problems. if (isFileURI(wasmBinaryFile)) { err('warning: Loading from a file URI (' + wasmBinaryFile + ') is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing'); } abort(reason); }); } function instantiateAsync() { // if (!wasmBinary && // typeof WebAssembly.instantiateStreaming == 'function' && // !isDataURI(wasmBinaryFile) && // // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously. // !isFileURI(wasmBinaryFile) && // // Avoid instantiateStreaming() on Node.js environment for now, as while // // Node.js v18.1.0 implements it, it does not have a full fetch() // // implementation yet. // // // // Reference: // // https://github.com/emscripten-core/emscripten/pull/16917 // !ENVIRONMENT_IS_NODE && // typeof fetch == 'function') { // return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) { // // Suppress closure warning here since the upstream definition for // // instantiateStreaming only allows Promise rather than // // an actual Response. // // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed. // /** @suppress {checkTypes} */ // var result = WebAssembly.instantiateStreaming(response, info); // return result.then( // receiveInstantiationResult, // function(reason) { // // We expect the most common failure cause to be a bad MIME type for the binary, // // in which case falling back to ArrayBuffer instantiation should work. // err('wasm streaming compile failed: ' + reason); // err('falling back to ArrayBuffer instantiation'); // return instantiateArrayBuffer(receiveInstantiationResult); // }); // }); // } else { return instantiateArrayBuffer(receiveInstantiationResult); //} } // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback // to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel // to any other async startup actions they are performing. // Also pthreads and wasm workers initialize the wasm instance through this path. if (Module['instantiateWasm']) { try { var exports = Module['instantiateWasm'](info, receiveInstance); return exports; } catch(e) { err('Module.instantiateWasm callback failed with error: ' + e); // If instantiation fails, reject the module ready promise. readyPromiseReject(e); } } // If instantiation fails, reject the module ready promise. instantiateAsync().catch(readyPromiseReject); return {}; // no exports yet; we'll fill them in later } function array_bounds_check_error(idx,size) { throw 'Array index ' + idx + ' out of bounds: [0,' + size + ')'; } /** @constructor */ function ExitStatus(status) { this.name = 'ExitStatus'; this.message = 'Program terminated with exit(' + status + ')'; this.status = status; } function callRuntimeCallbacks(callbacks) { while (callbacks.length > 0) { // Pass the module as the first argument. callbacks.shift()(Module); } } function ptrToString(ptr) { return '0x' + ptr.toString(16).padStart(8, '0'); } function warnOnce(text) { if (!warnOnce.shown) warnOnce.shown = {}; if (!warnOnce.shown[text]) { warnOnce.shown[text] = 1; if (ENVIRONMENT_IS_NODE) text = 'warning: ' + text; err(text); } } function _abort() { abort('native code called abort()'); } function getHeapMax() { // Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate // full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side // for any code that deals with heap sizes, which would require special // casing all heap size related code to treat 0 specially. return 2147483648; } function emscripten_realloc_buffer(size) { try { // round size grow request up to wasm page size (fixed 64KB per spec) wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16); // .grow() takes a delta compared to the previous size updateGlobalBufferAndViews(wasmMemory.buffer); return 1 /*success*/; } catch(e) { err('emscripten_realloc_buffer: Attempted to grow heap from ' + buffer.byteLength + ' bytes to ' + size + ' bytes, but got error: ' + e); } // implicit 0 return to save code size (caller will cast "undefined" into 0 // anyhow) } function _emscripten_resize_heap(requestedSize) { var oldSize = HEAPU8.length; requestedSize = requestedSize >>> 0; // With multithreaded builds, races can happen (another thread might increase the size // in between), so return a failure, and let the caller retry. assert(requestedSize > oldSize); // Memory resize rules: // 1. Always increase heap size to at least the requested size, rounded up // to next page multiple. // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap // geometrically: increase the heap size according to // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most // overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB). // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap // linearly: increase the heap size by at least // MEMORY_GROWTH_LINEAR_STEP bytes. // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by // MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest // 4. If we were unable to allocate as much memory, it may be due to // over-eager decision to excessively reserve due to (3) above. // Hence if an allocation fails, cut down on the amount of excess // growth, in an attempt to succeed to perform a smaller allocation. // A limit is set for how much we can grow. We should not exceed that // (the wasm binary specifies it, so if we tried, we'd fail anyhow). var maxHeapSize = getHeapMax(); if (requestedSize > maxHeapSize) { err('Cannot enlarge memory, asked to go up to ' + requestedSize + ' bytes, but the limit is ' + maxHeapSize + ' bytes!'); return false; } let alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple; // Loop through potential heap size increases. If we attempt a too eager // reservation that fails, cut down on the attempted size and reserve a // smaller bump instead. (max 3 times, chosen somewhat arbitrarily) for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth // but limit overreserving (default to capping at +96MB overgrowth at most) overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 ); var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)); var replacement = emscripten_realloc_buffer(newSize); if (replacement) { return true; } } err('Failed to grow the heap from ' + oldSize + ' bytes to ' + newSize + ' bytes, not enough memory!'); return false; } function _fd_close(fd) { abort('fd_close called without SYSCALLS_REQUIRE_FILESYSTEM'); } function _fd_seek(fd, offset_low, offset_high, whence, newOffset) { return 70; } var printCharBuffers = [null,[],[]]; function printChar(stream, curr) { var buffer = printCharBuffers[stream]; assert(buffer); if (curr === 0 || curr === 10) { (stream === 1 ? out : err)(UTF8ArrayToString(buffer, 0)); buffer.length = 0; } else { buffer.push(curr); } } function _fd_write(fd, iov, iovcnt, pnum) { // hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0 var num = 0; for (var i = 0; i < iovcnt; i++) { var ptr = HEAPU32[((iov)>>2)]; var len = HEAPU32[(((iov)+(4))>>2)]; iov += 8; for (var j = 0; j < len; j++) { printChar(fd, HEAPU8[ptr+j]); } num += len; } HEAPU32[((pnum)>>2)] = num; return 0; } function checkIncomingModuleAPI() { ignoredModuleProp('fetchSettings'); } var asmLibraryArg = { "abort": _abort, "array_bounds_check_error": array_bounds_check_error, "emscripten_resize_heap": _emscripten_resize_heap, "fd_close": _fd_close, "fd_seek": _fd_seek, "fd_write": _fd_write }; createWasm(); /** @type {function(...*):?} */ Module["___wasm_call_ctors"] = createExportWrapper("__wasm_call_ctors"); /** @type {function(...*):?} */ var _emscripten_bind_VoidPtr___destroy___0 = Module["_emscripten_bind_VoidPtr___destroy___0"] = createExportWrapper("emscripten_bind_VoidPtr___destroy___0"); /** @type {function(...*):?} */ var _emscripten_bind_Crc64Hash_Crc64Hash_0 = Module["_emscripten_bind_Crc64Hash_Crc64Hash_0"] = createExportWrapper("emscripten_bind_Crc64Hash_Crc64Hash_0"); /** @type {function(...*):?} */ var _emscripten_bind_Crc64Hash_OnAppend_2 = Module["_emscripten_bind_Crc64Hash_OnAppend_2"] = createExportWrapper("emscripten_bind_Crc64Hash_OnAppend_2"); /** @type {function(...*):?} */ var _emscripten_bind_Crc64Hash_OnFinal_3 = Module["_emscripten_bind_Crc64Hash_OnFinal_3"] = createExportWrapper("emscripten_bind_Crc64Hash_OnFinal_3"); /** @type {function(...*):?} */ var _emscripten_bind_Crc64Hash___destroy___0 = Module["_emscripten_bind_Crc64Hash___destroy___0"] = createExportWrapper("emscripten_bind_Crc64Hash___destroy___0"); /** @type {function(...*):?} */ Module["___errno_location"] = createExportWrapper("__errno_location"); /** @type {function(...*):?} */ Module["_fflush"] = createExportWrapper("fflush"); /** @type {function(...*):?} */ Module["_malloc"] = createExportWrapper("malloc"); /** @type {function(...*):?} */ Module["_free"] = createExportWrapper("free"); /** @type {function(...*):?} */ var _emscripten_stack_init = Module["_emscripten_stack_init"] = function() { return (_emscripten_stack_init = Module["_emscripten_stack_init"] = Module["asm"]["emscripten_stack_init"]).apply(null, arguments); }; /** @type {function(...*):?} */ Module["_emscripten_stack_get_free"] = function() { return (Module["_emscripten_stack_get_free"] = Module["asm"]["emscripten_stack_get_free"]).apply(null, arguments); }; /** @type {function(...*):?} */ Module["_emscripten_stack_get_base"] = function() { return (Module["_emscripten_stack_get_base"] = Module["asm"]["emscripten_stack_get_base"]).apply(null, arguments); }; /** @type {function(...*):?} */ var _emscripten_stack_get_end = Module["_emscripten_stack_get_end"] = function() { return (_emscripten_stack_get_end = Module["_emscripten_stack_get_end"] = Module["asm"]["emscripten_stack_get_end"]).apply(null, arguments); }; /** @type {function(...*):?} */ Module["stackSave"] = createExportWrapper("stackSave"); /** @type {function(...*):?} */ Module["stackRestore"] = createExportWrapper("stackRestore"); /** @type {function(...*):?} */ Module["stackAlloc"] = createExportWrapper("stackAlloc"); /** @type {function(...*):?} */ Module["_emscripten_stack_get_current"] = function() { return (Module["_emscripten_stack_get_current"] = Module["asm"]["emscripten_stack_get_current"]).apply(null, arguments); }; /** @type {function(...*):?} */ Module["dynCall_jiji"] = createExportWrapper("dynCall_jiji"); Module['___start_em_js'] = 5261488; Module['___stop_em_js'] = 5261586; // === Auto-generated postamble setup entry stuff === var unexportedRuntimeSymbols = [ 'run', 'UTF8ArrayToString', 'UTF8ToString', 'stringToUTF8Array', 'stringToUTF8', 'lengthBytesUTF8', 'addOnPreRun', 'addOnInit', 'addOnPreMain', 'addOnExit', 'addOnPostRun', 'addRunDependency', 'removeRunDependency', 'FS_createFolder', 'FS_createPath', 'FS_createDataFile', 'FS_createPreloadedFile', 'FS_createLazyFile', 'FS_createLink', 'FS_createDevice', 'FS_unlink', 'getLEB', 'getFunctionTables', 'alignFunctionTables', 'registerFunctions', 'prettyPrint', 'getCompilerSetting', 'out', 'err', 'callMain', 'abort', 'keepRuntimeAlive', 'wasmMemory', 'stackAlloc', 'stackSave', 'stackRestore', 'getTempRet0', 'setTempRet0', 'writeStackCookie', 'checkStackCookie', 'ptrToString', 'zeroMemory', 'stringToNewUTF8', 'exitJS', 'getHeapMax', 'emscripten_realloc_buffer', 'ENV', 'ERRNO_CODES', 'ERRNO_MESSAGES', 'setErrNo', 'inetPton4', 'inetNtop4', 'inetPton6', 'inetNtop6', 'readSockaddr', 'writeSockaddr', 'DNS', 'getHostByName', 'Protocols', 'Sockets', 'getRandomDevice', 'warnOnce', 'traverseStack', 'UNWIND_CACHE', 'convertPCtoSourceLocation', 'readEmAsmArgsArray', 'readEmAsmArgs', 'runEmAsmFunction', 'runMainThreadEmAsm', 'jstoi_q', 'jstoi_s', 'getExecutableName', 'listenOnce', 'autoResumeAudioContext', 'dynCallLegacy', 'getDynCaller', 'dynCall', 'handleException', 'runtimeKeepalivePush', 'runtimeKeepalivePop', 'callUserCallback', 'maybeExit', 'safeSetTimeout', 'asmjsMangle', 'asyncLoad', 'alignMemory', 'mmapAlloc', 'writeI53ToI64', 'writeI53ToI64Clamped', 'writeI53ToI64Signaling', 'writeI53ToU64Clamped', 'writeI53ToU64Signaling', 'readI53FromI64', 'readI53FromU64', 'convertI32PairToI53', 'convertI32PairToI53Checked', 'convertU32PairToI53', 'getCFunc', 'ccall', 'cwrap', 'uleb128Encode', 'sigToWasmTypes', 'generateFuncType', 'convertJsFunctionToWasm', 'freeTableIndexes', 'functionsInTableMap', 'getEmptyTableSlot', 'updateTableMap', 'addFunction', 'removeFunction', 'reallyNegative', 'unSign', 'strLen', 'reSign', 'formatString', 'setValue', 'getValue', 'PATH', 'PATH_FS', 'intArrayFromString', 'intArrayToString', 'AsciiToString', 'stringToAscii', 'UTF16Decoder', 'UTF16ToString', 'stringToUTF16', 'lengthBytesUTF16', 'UTF32ToString', 'stringToUTF32', 'lengthBytesUTF32', 'allocateUTF8', 'allocateUTF8OnStack', 'writeStringToMemory', 'writeArrayToMemory', 'writeAsciiToMemory', 'SYSCALLS', 'getSocketFromFD', 'getSocketAddress', 'JSEvents', 'registerKeyEventCallback', 'specialHTMLTargets', 'maybeCStringToJsString', 'findEventTarget', 'findCanvasEventTarget', 'getBoundingClientRect', 'fillMouseEventData', 'registerMouseEventCallback', 'registerWheelEventCallback', 'registerUiEventCallback', 'registerFocusEventCallback', 'fillDeviceOrientationEventData', 'registerDeviceOrientationEventCallback', 'fillDeviceMotionEventData', 'registerDeviceMotionEventCallback', 'screenOrientation', 'fillOrientationChangeEventData', 'registerOrientationChangeEventCallback', 'fillFullscreenChangeEventData', 'registerFullscreenChangeEventCallback', 'JSEvents_requestFullscreen', 'JSEvents_resizeCanvasForFullscreen', 'registerRestoreOldStyle', 'hideEverythingExceptGivenElement', 'restoreHiddenElements', 'setLetterbox', 'currentFullscreenStrategy', 'restoreOldWindowedStyle', 'softFullscreenResizeWebGLRenderTarget', 'doRequestFullscreen', 'fillPointerlockChangeEventData', 'registerPointerlockChangeEventCallback', 'registerPointerlockErrorEventCallback', 'requestPointerLock', 'fillVisibilityChangeEventData', 'registerVisibilityChangeEventCallback', 'registerTouchEventCallback', 'fillGamepadEventData', 'registerGamepadEventCallback', 'registerBeforeUnloadEventCallback', 'fillBatteryEventData', 'battery', 'registerBatteryEventCallback', 'setCanvasElementSize', 'getCanvasElementSize', 'demangle', 'demangleAll', 'jsStackTrace', 'stackTrace', 'ExitStatus', 'getEnvStrings', 'checkWasiClock', 'flush_NO_FILESYSTEM', 'dlopenMissingError', 'createDyncallWrapper', 'setImmediateWrapped', 'clearImmediateWrapped', 'polyfillSetImmediate', 'uncaughtExceptionCount', 'exceptionLast', 'exceptionCaught', 'ExceptionInfo', 'exception_addRef', 'exception_decRef', 'Browser', 'setMainLoop', 'wget', 'FS', 'MEMFS', 'TTY', 'PIPEFS', 'SOCKFS', '_setNetworkCallback', 'tempFixedLengthArray', 'miniTempWebGLFloatBuffers', 'heapObjectForWebGLType', 'heapAccessShiftForWebGLHeap', 'GL', 'emscriptenWebGLGet', 'computeUnpackAlignedImageSize', 'emscriptenWebGLGetTexPixelData', 'emscriptenWebGLGetUniform', 'webglGetUniformLocation', 'webglPrepareUniformLocationsBeforeFirstUse', 'webglGetLeftBracePos', 'emscriptenWebGLGetVertexAttrib', 'writeGLArray', 'AL', 'SDL_unicode', 'SDL_ttfContext', 'SDL_audio', 'SDL', 'SDL_gfx', 'GLUT', 'EGL', 'GLFW_Window', 'GLFW', 'GLEW', 'IDBStore', 'runAndAbortIfError', 'ALLOC_NORMAL', 'ALLOC_STACK', 'allocate', ]; unexportedRuntimeSymbols.forEach(unexportedRuntimeSymbol); var missingLibrarySymbols = [ 'zeroMemory', 'stringToNewUTF8', 'exitJS', 'setErrNo', 'inetPton4', 'inetNtop4', 'inetPton6', 'inetNtop6', 'readSockaddr', 'writeSockaddr', 'getHostByName', 'getRandomDevice', 'traverseStack', 'convertPCtoSourceLocation', 'readEmAsmArgs', 'runEmAsmFunction', 'runMainThreadEmAsm', 'jstoi_q', 'jstoi_s', 'getExecutableName', 'listenOnce', 'autoResumeAudioContext', 'dynCallLegacy', 'getDynCaller', 'dynCall', 'handleException', 'runtimeKeepalivePush', 'runtimeKeepalivePop', 'callUserCallback', 'maybeExit', 'safeSetTimeout', 'asmjsMangle', 'asyncLoad', 'alignMemory', 'mmapAlloc', 'writeI53ToI64', 'writeI53ToI64Clamped', 'writeI53ToI64Signaling', 'writeI53ToU64Clamped', 'writeI53ToU64Signaling', 'readI53FromI64', 'readI53FromU64', 'convertI32PairToI53', 'convertU32PairToI53', 'getCFunc', 'ccall', 'cwrap', 'uleb128Encode', 'sigToWasmTypes', 'generateFuncType', 'convertJsFunctionToWasm', 'getEmptyTableSlot', 'updateTableMap', 'addFunction', 'removeFunction', 'reallyNegative', 'unSign', 'strLen', 'reSign', 'formatString', 'intArrayToString', 'AsciiToString', 'stringToAscii', 'UTF16ToString', 'stringToUTF16', 'lengthBytesUTF16', 'UTF32ToString', 'stringToUTF32', 'lengthBytesUTF32', 'allocateUTF8', 'allocateUTF8OnStack', 'writeStringToMemory', 'writeArrayToMemory', 'writeAsciiToMemory', 'getSocketFromFD', 'getSocketAddress', 'registerKeyEventCallback', 'maybeCStringToJsString', 'findEventTarget', 'findCanvasEventTarget', 'getBoundingClientRect', 'fillMouseEventData', 'registerMouseEventCallback', 'registerWheelEventCallback', 'registerUiEventCallback', 'registerFocusEventCallback', 'fillDeviceOrientationEventData', 'registerDeviceOrientationEventCallback', 'fillDeviceMotionEventData', 'registerDeviceMotionEventCallback', 'screenOrientation', 'fillOrientationChangeEventData', 'registerOrientationChangeEventCallback', 'fillFullscreenChangeEventData', 'registerFullscreenChangeEventCallback', 'JSEvents_requestFullscreen', 'JSEvents_resizeCanvasForFullscreen', 'registerRestoreOldStyle', 'hideEverythingExceptGivenElement', 'restoreHiddenElements', 'setLetterbox', 'softFullscreenResizeWebGLRenderTarget', 'doRequestFullscreen', 'fillPointerlockChangeEventData', 'registerPointerlockChangeEventCallback', 'registerPointerlockErrorEventCallback', 'requestPointerLock', 'fillVisibilityChangeEventData', 'registerVisibilityChangeEventCallback', 'registerTouchEventCallback', 'fillGamepadEventData', 'registerGamepadEventCallback', 'registerBeforeUnloadEventCallback', 'fillBatteryEventData', 'battery', 'registerBatteryEventCallback', 'setCanvasElementSize', 'getCanvasElementSize', 'demangle', 'demangleAll', 'jsStackTrace', 'stackTrace', 'getEnvStrings', 'checkWasiClock', 'createDyncallWrapper', 'setImmediateWrapped', 'clearImmediateWrapped', 'polyfillSetImmediate', 'ExceptionInfo', 'exception_addRef', 'exception_decRef', 'setMainLoop', '_setNetworkCallback', 'heapObjectForWebGLType', 'heapAccessShiftForWebGLHeap', 'emscriptenWebGLGet', 'computeUnpackAlignedImageSize', 'emscriptenWebGLGetTexPixelData', 'emscriptenWebGLGetUniform', 'webglGetUniformLocation', 'webglPrepareUniformLocationsBeforeFirstUse', 'webglGetLeftBracePos', 'emscriptenWebGLGetVertexAttrib', 'writeGLArray', 'SDL_unicode', 'SDL_ttfContext', 'SDL_audio', 'GLFW_Window', 'runAndAbortIfError', 'ALLOC_NORMAL', 'ALLOC_STACK', 'allocate', ]; missingLibrarySymbols.forEach(missingLibrarySymbol); var calledRun; dependenciesFulfilled = function runCaller() { // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false) if (!calledRun) run(); if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled }; function stackCheckInit() { // This is normally called automatically during __wasm_call_ctors but need to // get these values before even running any of the ctors so we call it redundantly // here. _emscripten_stack_init(); // TODO(sbc): Move writeStackCookie to native to to avoid this. writeStackCookie(); } /** @type {function(Array=)} */ function run(args) { if (runDependencies > 0) { return; } stackCheckInit(); preRun(); // a preRun added a dependency, run will be called later if (runDependencies > 0) { return; } function doRun() { // run may have just been called through dependencies being fulfilled just in this very frame, // or while the async setStatus time below was happening if (calledRun) return; calledRun = true; Module['calledRun'] = true; if (ABORT) return; initRuntime(); readyPromiseResolve(Module); if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); assert(!Module['_main'], 'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]'); postRun(); } if (Module['setStatus']) { Module['setStatus']('Running...'); setTimeout(function() { setTimeout(function() { Module['setStatus'](''); }, 1); doRun(); }, 1); } else { doRun(); } checkStackCookie(); } if (Module['preInit']) { if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']]; while (Module['preInit'].length > 0) { Module['preInit'].pop()(); } } run(); // Bindings utilities /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */ function WrapperObject() { } WrapperObject.prototype = Object.create(WrapperObject.prototype); WrapperObject.prototype.constructor = WrapperObject; WrapperObject.prototype.__class__ = WrapperObject; WrapperObject.__cache__ = {}; Module['WrapperObject'] = WrapperObject; /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) @param {*=} __class__ */ function getCache(__class__) { return (__class__ || WrapperObject).__cache__; } Module['getCache'] = getCache; /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) @param {*=} __class__ */ function wrapPointer(ptr, __class__) { var cache = getCache(__class__); var ret = cache[ptr]; if (ret) return ret; ret = Object.create((__class__ || WrapperObject).prototype); ret.ptr = ptr; return cache[ptr] = ret; } Module['wrapPointer'] = wrapPointer; /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */ function castObject(obj, __class__) { return wrapPointer(obj.ptr, __class__); } Module['castObject'] = castObject; Module['NULL'] = wrapPointer(0); /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */ function destroy(obj) { if (!obj['__destroy__']) throw 'Error: Cannot destroy object. (Did you create it yourself?)'; obj['__destroy__'](); // Remove from cache, so the object can be GC'd and refs added onto it released delete getCache(obj.__class__)[obj.ptr]; } Module['destroy'] = destroy; /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */ function compare(obj1, obj2) { return obj1.ptr === obj2.ptr; } Module['compare'] = compare; /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */ function getPointer(obj) { return obj.ptr; } Module['getPointer'] = getPointer; /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */ function getClass(obj) { return obj.__class__; } Module['getClass'] = getClass; // VoidPtr /** @suppress {undefinedVars, duplicate} @this{Object} */function VoidPtr() { throw "cannot construct a VoidPtr, no constructor in IDL" } VoidPtr.prototype = Object.create(WrapperObject.prototype); VoidPtr.prototype.constructor = VoidPtr; VoidPtr.prototype.__class__ = VoidPtr; VoidPtr.__cache__ = {}; Module['VoidPtr'] = VoidPtr; VoidPtr.prototype['__destroy__'] = VoidPtr.prototype.__destroy__ = /** @suppress {undefinedVars, duplicate} @this{Object} */function() { var self = this.ptr; _emscripten_bind_VoidPtr___destroy___0(self); }; // Crc64Hash /** @suppress {undefinedVars, duplicate} @this{Object} */function Crc64Hash() { this.ptr = _emscripten_bind_Crc64Hash_Crc64Hash_0(); getCache(Crc64Hash)[this.ptr] = this; }Crc64Hash.prototype = Object.create(WrapperObject.prototype); Crc64Hash.prototype.constructor = Crc64Hash; Crc64Hash.prototype.__class__ = Crc64Hash; Crc64Hash.__cache__ = {}; Module['Crc64Hash'] = Crc64Hash; Crc64Hash.prototype['OnAppend'] = Crc64Hash.prototype.OnAppend = /** @suppress {undefinedVars, duplicate} @this{Object} */function(data, length) { var self = this.ptr; if (data && typeof data === 'object') data = data.ptr; if (length && typeof length === 'object') length = length.ptr; _emscripten_bind_Crc64Hash_OnAppend_2(self, data, length); }; Crc64Hash.prototype['OnFinal'] = Crc64Hash.prototype.OnFinal = /** @suppress {undefinedVars, duplicate} @this{Object} */function(data, length, result) { var self = this.ptr; if (data && typeof data === 'object') data = data.ptr; if (length && typeof length === 'object') length = length.ptr; if (result && typeof result === 'object') result = result.ptr; _emscripten_bind_Crc64Hash_OnFinal_3(self, data, length, result); }; Crc64Hash.prototype['__destroy__'] = Crc64Hash.prototype.__destroy__ = /** @suppress {undefinedVars, duplicate} @this{Object} */function() { var self = this.ptr; _emscripten_bind_Crc64Hash___destroy___0(self); }; return NativeCRC64.ready } ); })(); // ESM-EXPORT-END // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // @ts-expect-error the crc64 js file is auto generated /** * Class used to calculator CRC64 checksum */ class StorageCRC64Calculator { nativeCrc64Hash; static nativeInstance; constructor() { this.nativeCrc64Hash = new StorageCRC64Calculator.nativeInstance.Crc64Hash(); } static initPromise; /** * Initialize environment for CRC64 checksum calculator */ static async init() { if (!this.initPromise) { this.initPromise = NativeCRC64().then((instance) => { this.nativeInstance = instance; return; }); } return this.initPromise; } /** * Append data for CRC64 checksum calculator * @param body - content to be append * @param length - length of the content */ append(body, length) { const ptr = StorageCRC64Calculator.nativeInstance._malloc(length); StorageCRC64Calculator.nativeInstance.HEAPU8.set(body, ptr); this.nativeCrc64Hash.OnAppend(ptr, length); StorageCRC64Calculator.nativeInstance._free(ptr); } /** * Complete CRC64 checksum calculating and get the final result. * @param body - * @param length - * @returns */ final(body, length) { const ptr = StorageCRC64Calculator.nativeInstance._malloc(length); StorageCRC64Calculator.nativeInstance.HEAPU8.set(body, ptr); const result = StorageCRC64Calculator.nativeInstance._malloc(8); this.nativeCrc64Hash.OnFinal(ptr, length, result); StorageCRC64Calculator.nativeInstance._free(ptr); const resultArray = new Uint8Array(8); resultArray.set(StorageCRC64Calculator.nativeInstance.HEAPU8.subarray(result, result + 8)); StorageCRC64Calculator.nativeInstance._free(result); return resultArray; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Signals the end of a stream by pushing null. * In Node.js, this is required to signal the end of a Readable stream. * @internal */ function signalStreamEnd(pushData) { pushData(null); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const MESSAGE_VERSION$1 = 1; const MESSAGE_HEADER_LENGTH$1 = 13; const SEGMENT_HEADER_LENGTH$1 = 10; const FOOTER_LENGTH$1 = 8; const MAX_SEGMENT_CONTENT_LENGTH = 4 * 1024 * 1024; var SMRegion$1; (function (SMRegion) { SMRegion[SMRegion["StreamHeader"] = 0] = "StreamHeader"; SMRegion[SMRegion["StreamFooter"] = 1] = "StreamFooter"; SMRegion[SMRegion["SegmentHeader"] = 2] = "SegmentHeader"; SMRegion[SMRegion["SegmentFooter"] = 3] = "SegmentFooter"; SMRegion[SMRegion["SegmentContent"] = 4] = "SegmentContent"; SMRegion[SMRegion["Completed"] = 5] = "Completed"; })(SMRegion$1 || (SMRegion$1 = {})); class StructuredMessageEncoding { pushData; contentLength; messageLength; constructor(pushData, contentLength) { this.pushData = pushData; this.contentLength = contentLength; this.contentOffset = 0; this.currentDataOffset = 0; this.segmentsCount = Math.ceil(this.contentLength / MAX_SEGMENT_CONTENT_LENGTH); this.messageLength = this.contentLength + MESSAGE_HEADER_LENGTH$1 + (SEGMENT_HEADER_LENGTH$1 + FOOTER_LENGTH$1) * this.segmentsCount + FOOTER_LENGTH$1; this.messageHeaderBuffer = new Uint8Array(MESSAGE_HEADER_LENGTH$1); this.segmentNumber = 0; this.segmentContentLength = 0; this.segmentContentOffset = 0; this.state = SMRegion$1.StreamHeader; this.segmentCrc64 = new StorageCRC64Calculator(); this.messageCrc64 = new StorageCRC64Calculator(); } currentDataOffset; contentOffset; segmentsCount; messageHeaderBuffer; segmentNumber; segmentContentLength; segmentContentOffset; segmentCrc64; messageCrc64; state; sourceDataHandler = (data) => { this.currentDataOffset = 0; if (this.state === SMRegion$1.StreamHeader) { this.handlingMessageHeader(); } while (this.segmentNumber < this.segmentsCount) { this.segmentContentLength = Math.min(MAX_SEGMENT_CONTENT_LENGTH, this.contentLength - this.contentOffset); if (this.state === SMRegion$1.SegmentHeader) { this.handlingSegmentHeader(); } if (this.state === SMRegion$1.SegmentContent) { this.handlingSegmentContent(data); } if (this.state === SMRegion$1.SegmentFooter) { this.handlingSegmentFooter(); this.contentOffset += this.segmentContentLength; } if (this.currentDataOffset === data.length) { break; } } if (this.state === SMRegion$1.StreamFooter) { this.handlingMessageFooter(); } }; handlingMessageHeader() { this.messageHeaderBuffer[0] = MESSAGE_VERSION$1; this.fillInt64(this.messageHeaderBuffer, 1, this.messageLength); // content length this.fillInt16(this.messageHeaderBuffer, 9, 1); this.fillInt16(this.messageHeaderBuffer, 11, this.segmentsCount); this.pushData(this.messageHeaderBuffer); this.state = SMRegion$1.SegmentHeader; } handlingSegmentHeader() { const segmentHeaderBuffer = new Uint8Array(SEGMENT_HEADER_LENGTH$1); this.fillInt16(segmentHeaderBuffer, 0, this.segmentNumber + 1); this.fillInt64(segmentHeaderBuffer, 2, this.segmentContentLength); this.segmentContentOffset = 0; this.pushData(segmentHeaderBuffer); this.state = SMRegion$1.SegmentContent; } handlingSegmentContent(data) { const length = Math.min(this.segmentContentLength - this.segmentContentOffset, data.length - this.currentDataOffset); if (length !== 0) { const current_content = Uint8Array.prototype.slice.call(data, this.currentDataOffset, this.currentDataOffset + length); this.messageCrc64.append(current_content, length); this.segmentCrc64.append(current_content, length); this.pushData(current_content); } this.segmentContentOffset += length; this.currentDataOffset += length; if (this.segmentContentOffset === this.segmentContentLength) { this.state = SMRegion$1.SegmentFooter; } } handlingSegmentFooter() { const crc64Result = this.segmentCrc64.final(new Uint8Array([]), 0); this.pushData(crc64Result); this.segmentCrc64 = new StorageCRC64Calculator(); ++this.segmentNumber; if (this.segmentNumber === this.segmentsCount) { this.state = SMRegion$1.StreamFooter; } else { this.state = SMRegion$1.SegmentHeader; } } handlingMessageFooter() { const crc64Result = this.messageCrc64.final(new Uint8Array([]), 0); this.pushData(crc64Result); signalStreamEnd(this.pushData); this.state = SMRegion$1.Completed; } fillInt64(buffer, offset, input) { if (buffer.length < offset + 8) { throw new Error("Uint8Array length is not expected."); } const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 8); view.setBigUint64(0, BigInt(input), true); } fillInt16(buffer, offset, input) { if (buffer.length < offset + 2) { throw new Error("Uint8Array length is not expected."); } const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 2); view.setUint16(0, input, true); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function isNodeReadableStream(source) { return (source !== null && source instanceof require$$0$5 && typeof source._read === "function" && typeof source._readableState === "object" && typeof source.pipe === "function"); } /** * * To encode structured body for CRC64 content validtion in storage uploading. * @param source - * @param contentLength - * @returns */ async function structuredMessageEncoding(source, contentLength) { if (source === null) { return { body: source, encodedContentLength: contentLength, }; } if (isNodeReadableStream(source)) { const encodingMessage = new StructuredMessageEncodingStream(source, contentLength, {}); return { body: encodingMessage, encodedContentLength: encodingMessage.messageLength(), }; } if (typeof source === "function") { const encodingMessage = new StructuredMessageEncodingStream(source(), contentLength, {}); return { body: encodingMessage, encodedContentLength: encodingMessage.messageLength(), }; } if (source instanceof Blob) { const encoding = await BrowserStream(source, contentLength); return { body: encoding.content, encodedContentLength: encoding.encodedContentLength, }; } if (typeof source === "string") { const s = new Readable$1(); s._read = () => { }; s.push(source); s.push(null); const stringContentLength = Buffer.byteLength(source); const encodingMessage = await new StructuredMessageEncodingStream(s, stringContentLength, {}); return { body: encodingMessage, encodedContentLength: encodingMessage.messageLength(), }; } if (source instanceof ArrayBuffer) { const stream = Readable$1.from(Buffer.from(source)); const encodingMessage = await new StructuredMessageEncodingStream(stream, contentLength, {}); return { body: encodingMessage, encodedContentLength: encodingMessage.messageLength(), }; } if (source instanceof Buffer) { const stream = Readable$1.from(source); const encodingMessage = await new StructuredMessageEncodingStream(stream, contentLength, {}); return { body: encodingMessage, encodedContentLength: encodingMessage.messageLength(), }; } if (ArrayBuffer.isView(source)) { const stream = Readable$1.from(Buffer.from(source.buffer, source.byteOffset, source.byteLength)); const encodingMessage = await new StructuredMessageEncodingStream(stream, contentLength, {}); return { body: encodingMessage, encodedContentLength: encodingMessage.messageLength(), }; } throw new Error("The specified request body type is not supported for CRC64 checksum"); } async function pump(reader, controller, encodingStream) { const { done, value } = await reader.read(); // When no more data needs to be consumed, close the stream if (done) { controller.close(); return; } // Enqueue the next data chunk into our target stream encodingStream.sourceDataHandler(Buffer.from(value)); } async function BrowserStream(source, contentLength) { const sourceStream = source instanceof Blob ? source.stream() : source; const reader = sourceStream.getReader(); let encodingStream = undefined; const stream = new ReadableStream({ start(controller) { encodingStream = new StructuredMessageEncoding((data) => { controller.enqueue(data); }, contentLength); }, pull(controller) { pump(reader, controller, encodingStream) .then(() => { return; }) .catch(function (error) { controller.error(error); }); }, }); const response = new Response(stream); return { content: await response.blob(), encodedContentLength: encodingStream.messageLength, }; } class StructuredMessageEncodingStream extends Readable$1 { source; encodingMethods; constructor(source, contentLength, options) { super({ highWaterMark: options.highWaterMark }); this.source = source; this.encodingMethods = new StructuredMessageEncoding((dataToHandle) => { if (!this.push(dataToHandle)) { source.pause(); } }, contentLength); this.setSourceEventHandlers(); } messageLength() { return this.encodingMethods.messageLength; } setSourceEventHandlers() { this.source.on("data", this.sourceDataHandler); this.source.on("end", this.sourceErrorOrEndHandler); this.source.on("error", this.sourceErrorOrEndHandler); // needed for Node14 this.source.on("aborted", this.sourceAbortedHandler); } removeSourceEventHandlers() { this.source.removeListener("data", this.sourceDataHandler); this.source.removeListener("end", this.sourceErrorOrEndHandler); this.source.removeListener("error", this.sourceErrorOrEndHandler); this.source.removeListener("aborted", this.sourceAbortedHandler); } sourceDataHandler = (data) => { this.encodingMethods.sourceDataHandler(data); }; sourceAbortedHandler = () => { const abortError = new AbortError$1("The operation was aborted."); this.destroy(abortError); }; sourceErrorOrEndHandler = (err) => { if (err && err.name === "AbortError") { this.destroy(err); return; } // console.log( // `Source stream emits end or error, offset: ${ // this.offset // }, dest end : ${this.end}` // ); this.removeSourceEventHandlers(); }; _read() { this.source.resume(); } _destroy(error, callback) { // remove listener from source and release source this.removeSourceEventHandlers(); this.source.destroy(); callback(error === null ? undefined : error); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const MESSAGE_VERSION = 1; const MESSAGE_HEADER_LENGTH = 13; const SEGMENT_HEADER_LENGTH = 10; const FOOTER_LENGTH = 8; var SMRegion; (function (SMRegion) { SMRegion[SMRegion["StreamHeader"] = 0] = "StreamHeader"; SMRegion[SMRegion["StreamFooter"] = 1] = "StreamFooter"; SMRegion[SMRegion["SegmentHeader"] = 2] = "SegmentHeader"; SMRegion[SMRegion["SegmentFooter"] = 3] = "SegmentFooter"; SMRegion[SMRegion["SegmentContent"] = 4] = "SegmentContent"; })(SMRegion || (SMRegion = {})); class StructuredMessageDecoding { pushData; segmentsCount; // private currentState: SMRegion; currentOffset; currentDataOffset; messageHeaderBuffer; messageHeaderOffset; segmentNumber; segmentHeaderOffset; segmentHeaderBuffer; segmentContentOffset; segmentContentLength; segmentFooterOffset; segmentFooterBuffer; messageFooterOffset; messageFooterBuffer; segmentCrc64; messageCrc64; state; constructor(pushData) { this.pushData = pushData; this.currentOffset = 0; this.segmentsCount = 0; this.messageHeaderOffset = 0; this.messageHeaderBuffer = new Uint8Array(MESSAGE_HEADER_LENGTH); this.currentDataOffset = 0; this.segmentNumber = 0; this.segmentHeaderOffset = 0; this.segmentHeaderBuffer = new Uint8Array(SEGMENT_HEADER_LENGTH); this.segmentContentOffset = 0; this.segmentContentLength = 0; this.state = SMRegion.StreamHeader; this.segmentFooterOffset = 0; this.segmentFooterBuffer = new Uint8Array(FOOTER_LENGTH); this.messageFooterOffset = 0; this.messageFooterBuffer = new Uint8Array(FOOTER_LENGTH); this.segmentCrc64 = new StorageCRC64Calculator(); this.messageCrc64 = new StorageCRC64Calculator(); } sourceDataHandler = (data) => { this.currentDataOffset = 0; if (this.state === SMRegion.StreamHeader) { this.parseMessageHeader(data); } while (this.segmentNumber < this.segmentsCount && this.currentDataOffset < data.length) { if (this.state === SMRegion.SegmentHeader) { this.parseSegmentHeader(data); } if (this.state === SMRegion.SegmentContent) { this.parseSegmentContent(data); } if (this.state === SMRegion.SegmentFooter) { this.parseSegmentFooter(data); } } if (this.state === SMRegion.StreamFooter) { this.parseMessageFooter(data); } }; parseMessageHeader(data) { const length = Math.min(MESSAGE_HEADER_LENGTH - this.messageHeaderOffset, data.length - this.currentDataOffset); this.messageHeaderBuffer.set(Uint8Array.prototype.slice.call(data, this.currentDataOffset, this.currentDataOffset + length), this.messageHeaderOffset); this.currentDataOffset += length; this.messageHeaderOffset += length; this.currentOffset += length; if (this.messageHeaderOffset === MESSAGE_HEADER_LENGTH) { const currentVersion = this.messageHeaderBuffer[0]; if (currentVersion !== MESSAGE_VERSION) { throw new Error("Unexpected message version"); } this.segmentsCount = this.toInt16(Uint8Array.prototype.slice.call(this.messageHeaderBuffer, 11, 13)); this.state = SMRegion.SegmentHeader; } } parseSegmentHeader(data) { const length = Math.min(SEGMENT_HEADER_LENGTH - this.segmentHeaderOffset, data.length - this.currentDataOffset); this.segmentHeaderBuffer.set(Uint8Array.prototype.slice.call(data, this.currentDataOffset, this.currentDataOffset + length), this.segmentHeaderOffset); this.currentDataOffset += length; this.segmentHeaderOffset += length; this.currentOffset += length; if (this.segmentHeaderOffset === SEGMENT_HEADER_LENGTH) { const currentSegmentNumber = this.toInt16(Uint8Array.prototype.slice.call(this.segmentHeaderBuffer, 0, 2)); if (currentSegmentNumber !== this.segmentNumber + 1) { throw new Error("Segment number is unexpected."); } this.segmentContentLength = this.toInt64(this.segmentHeaderBuffer, 2); this.segmentContentOffset = 0; this.state = SMRegion.SegmentContent; } } parseSegmentContent(data) { const length = Math.min(this.segmentContentLength - this.segmentContentOffset, data.length - this.currentDataOffset); const dataToHandle = Uint8Array.prototype.slice.call(data, this.currentDataOffset, this.currentDataOffset + length); this.segmentCrc64.append(dataToHandle, length); this.messageCrc64.append(dataToHandle, length); this.pushData(dataToHandle); this.currentDataOffset += length; this.segmentContentOffset += length; this.currentOffset += length; if (this.segmentContentOffset === this.segmentContentLength) { this.state = SMRegion.SegmentFooter; } } parseSegmentFooter(data) { const length = Math.min(FOOTER_LENGTH - this.segmentFooterOffset, data.length - this.currentDataOffset); this.segmentFooterBuffer.set(Uint8Array.prototype.slice.call(data, this.currentDataOffset, this.currentDataOffset + length), this.segmentFooterOffset); this.currentDataOffset += length; this.segmentFooterOffset += length; this.currentOffset += length; if (this.segmentFooterOffset === FOOTER_LENGTH) { const crc64Result = this.segmentCrc64.final(new Uint8Array([]), 0); if (!this.checkCrc64CheckSum(crc64Result, this.segmentFooterBuffer)) { throw new Error(`Segment check sum mismatch, segmentNumber: ${this.segmentNumber}`); } ++this.segmentNumber; if (this.segmentNumber === this.segmentsCount) { this.state = SMRegion.StreamFooter; } else { this.segmentHeaderOffset = 0; this.segmentFooterOffset = 0; this.segmentCrc64 = new StorageCRC64Calculator(); this.state = SMRegion.SegmentHeader; } } } parseMessageFooter(data) { const length = Math.min(FOOTER_LENGTH - this.messageFooterOffset, data.length - this.currentDataOffset); this.messageFooterBuffer.set(Uint8Array.prototype.slice.call(data, this.currentDataOffset, this.currentDataOffset + length), this.messageFooterOffset); this.currentDataOffset += length; this.messageFooterOffset += length; this.currentOffset += length; if (this.messageFooterOffset === FOOTER_LENGTH) { const crc64Result = this.messageCrc64.final(new Uint8Array([]), 0); if (!this.checkCrc64CheckSum(crc64Result, this.messageFooterBuffer)) { throw new Error("Check sum mismatch"); } this.pushData(null); } } toInt64(input, offset) { if (input.length < offset + 8) { throw new Error("CRC64 buffer error, something wrong with crc64 calculator"); } const view = new DataView(input.buffer, input.byteOffset + offset, 8); return Number(view.getBigUint64(0, true)); } toInt16(input) { if (input.length !== 2) { throw new Error("CRC64 buffer error, something wrong with crc64 calculator"); } return input[0] + input[1] * 256; } checkCrc64CheckSum(first, second) { if (first.length !== 8 || second.length !== 8) { throw new Error("CRC64 buffer error, something wrong with crc64 calculator"); } for (let index = 0; index < 8; ++index) { if (first[index] !== second[index]) { return false; } } return true; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * To decode structured body for CRC64 content validtion in storage downloading. * @param source - * @param options - * @returns */ function structuredMessageDecodingStream(source, options) { return new StructuredMessageDecodingStream(source, options); } class StructuredMessageDecodingStream extends Readable$1 { source; decodingMethods; constructor(source, options) { super({ highWaterMark: options.highWaterMark }); this.source = source; this.decodingMethods = new StructuredMessageDecoding((dataToHandle) => { if (!this.push(dataToHandle)) { source.pause(); } }); this.setSourceEventHandlers(); } _read() { this.source.resume(); } setSourceEventHandlers() { this.source.on("data", this.sourceDataHandler); this.source.on("end", this.sourceErrorOrEndHandler); this.source.on("error", this.sourceErrorOrEndHandler); // needed for Node14 this.source.on("aborted", this.sourceAbortedHandler); } removeSourceEventHandlers() { this.source.removeListener("data", this.sourceDataHandler); this.source.removeListener("end", this.sourceErrorOrEndHandler); this.source.removeListener("error", this.sourceErrorOrEndHandler); this.source.removeListener("aborted", this.sourceAbortedHandler); } sourceDataHandler = (data) => { try { this.decodingMethods.sourceDataHandler(data); } catch (err) { this.destroy(err); } }; sourceAbortedHandler = () => { const abortError = new AbortError$1("The operation was aborted."); this.destroy(abortError); }; sourceErrorOrEndHandler = (err) => { if (err) { this.destroy(err); return; } this.removeSourceEventHandlers(); }; _destroy(error, callback) { // remove listener from source and release source this.removeSourceEventHandlers(); this.source.destroy(); callback(error === null ? undefined : error); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. let _defaultHttpClient; function getCachedDefaultHttpClient() { if (!_defaultHttpClient) { _defaultHttpClient = createDefaultHttpClient(); } return _defaultHttpClient; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The base class from which all request policies derive. */ class BaseRequestPolicy { _nextPolicy; _options; /** * The main method to implement that manipulates a request/response. */ constructor( /** * The next policy in the pipeline. Each policy is responsible for executing the next one if the request is to continue through the pipeline. */ _nextPolicy, /** * The options that can be passed to a given request policy. */ _options) { this._nextPolicy = _nextPolicy; this._options = _options; } /** * Get whether or not a log with the provided log level should be logged. * @param logLevel - The log level of the log that will be logged. * @returns Whether or not a log with the provided log level should be logged. */ shouldLog(logLevel) { return this._options.shouldLog(logLevel); } /** * Attempt to log the provided message to the provided logger. If no logger was provided or if * the log level does not meat the logger's threshold, then nothing will be logged. * @param logLevel - The log level of this log. * @param message - The message of this log. */ log(logLevel, message) { this._options.log(logLevel, message); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * StorageBrowserPolicy will handle differences between Node.js and browser runtime, including: * * 1. Browsers cache GET/HEAD requests by adding conditional headers such as 'IF_MODIFIED_SINCE'. * StorageBrowserPolicy is a policy used to add a timestamp query to GET/HEAD request URL * thus avoid the browser cache. * * 2. Remove cookie header for security * * 3. Remove content-length header to avoid browsers warning * * In Node.js, this policy is a no-op pass-through. */ class StorageBrowserPolicy extends BaseRequestPolicy { /** * Creates an instance of StorageBrowserPolicy. * @param nextPolicy - * @param options - */ // The base class has a protected constructor. Adding a public one to enable constructing of this class. /* eslint-disable-next-line @typescript-eslint/no-useless-constructor*/ constructor(nextPolicy, options) { super(nextPolicy, options); } /** * Sends out request. * * @param request - */ async sendRequest(request) { return this._nextPolicy.sendRequest(request); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * StorageBrowserPolicyFactory is a factory class helping generating StorageBrowserPolicy objects. */ class StorageBrowserPolicyFactory { /** * Creates a StorageBrowserPolicyFactory object. * * @param nextPolicy - * @param options - */ create(nextPolicy, options) { return new StorageBrowserPolicy(nextPolicy, options); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Credential policy used to sign HTTP(S) requests before sending. This is an * abstract class. */ class CredentialPolicy extends BaseRequestPolicy { /** * Sends out request. * * @param request - */ sendRequest(request) { return this._nextPolicy.sendRequest(this.signRequest(request)); } /** * Child classes must implement this method with request signing. This method * will be executed in {@link sendRequest}. * * @param request - */ signRequest(request) { // Child classes must override this method with request signing. This method // will be executed in sendRequest(). return request; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * AnonymousCredentialPolicy is used with HTTP(S) requests that read public resources * or for use with Shared Access Signatures (SAS). */ class AnonymousCredentialPolicy extends CredentialPolicy { /** * Creates an instance of AnonymousCredentialPolicy. * @param nextPolicy - * @param options - */ // The base class has a protected constructor. Adding a public one to enable constructing of this class. /* eslint-disable-next-line @typescript-eslint/no-useless-constructor*/ constructor(nextPolicy, options) { super(nextPolicy, options); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Credential is an abstract class for Azure Storage HTTP requests signing. This * class will host an credentialPolicyCreator factory which generates CredentialPolicy. */ class Credential { /** * Creates a RequestPolicy object. * * @param _nextPolicy - * @param _options - */ create(_nextPolicy, _options) { throw new Error("Method should be implemented in children classes."); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * AnonymousCredential provides a credentialPolicyCreator member used to create * AnonymousCredentialPolicy objects. AnonymousCredentialPolicy is used with * HTTP(S) requests that read public resources or for use with Shared Access * Signatures (SAS). */ class AnonymousCredential extends Credential { /** * Creates an {@link AnonymousCredentialPolicy} object. * * @param nextPolicy - * @param options - */ create(nextPolicy, options) { return new AnonymousCredentialPolicy(nextPolicy, options); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const URLConstants$1 = { Parameters: { TIMEOUT: "timeout", }, }; const HeaderConstants = { AUTHORIZATION: "Authorization", CONTENT_ENCODING: "Content-Encoding", CONTENT_LANGUAGE: "Content-Language", CONTENT_LENGTH: "Content-Length", CONTENT_MD5: "Content-Md5", CONTENT_TYPE: "Content-Type", DATE: "date", IF_MATCH: "if-match", IF_MODIFIED_SINCE: "if-modified-since", IF_NONE_MATCH: "if-none-match", IF_UNMODIFIED_SINCE: "if-unmodified-since", PREFIX_FOR_STORAGE: "x-ms-", RANGE: "Range", X_MS_DATE: "x-ms-date", X_MS_CopySourceErrorCode: "x-ms-copy-source-error-code", }; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Set URL parameter name and value. If name exists in URL parameters, old value * will be replaced by name key. If not provide value, the parameter will be deleted. * * @param url - Source URL string * @param name - Parameter name * @param value - Parameter value * @returns An updated URL string */ function setURLParameter$1(url, name, value) { const urlParsed = new URL(url); const encodedName = encodeURIComponent(name); const encodedValue = value ? encodeURIComponent(value) : undefined; // mutating searchParams will change the encoding, so we have to do this ourselves const searchString = urlParsed.search === "" ? "?" : urlParsed.search; const searchPieces = []; for (const pair of searchString.slice(1).split("&")) { if (pair) { const [key] = pair.split("=", 2); if (key !== encodedName) { searchPieces.push(pair); } } } if (encodedValue) { searchPieces.push(`${encodedName}=${encodedValue}`); } urlParsed.search = searchPieces.length ? `?${searchPieces.join("&")}` : ""; return urlParsed.toString(); } /** * Set URL host. * * @param url - Source URL string * @param host - New host string * @returns An updated URL string */ function setURLHost(url, host) { const urlParsed = new URL(url); urlParsed.hostname = host; return urlParsed.toString(); } /** * Get URL path from an URL string. * * @param url - Source URL string */ function getURLPath(url) { try { const urlParsed = new URL(url); return urlParsed.pathname; } catch (e) { return undefined; } } /** * Get URL query key value pairs from an URL string. * * @param url - */ function getURLQueries(url) { let queryString = new URL(url).search; if (!queryString) { return {}; } queryString = queryString.trim(); queryString = queryString.startsWith("?") ? queryString.substring(1) : queryString; let querySubStrings = queryString.split("&"); querySubStrings = querySubStrings.filter((value) => { const indexOfEqual = value.indexOf("="); const lastIndexOfEqual = value.lastIndexOf("="); return (indexOfEqual > 0 && indexOfEqual === lastIndexOfEqual && lastIndexOfEqual < value.length - 1); }); const queries = {}; for (const querySubString of querySubStrings) { const splitResults = querySubString.split("="); const key = splitResults[0]; const value = splitResults[1]; queries[key] = value; } return queries; } /** * Delay specified time interval. * * @param timeInMs - * @param aborter - * @param abortError - */ async function delay(timeInMs, aborter, abortError) { return new Promise((resolve, reject) => { /* eslint-disable-next-line prefer-const */ let timeout; const abortHandler = () => { if (timeout !== undefined) { clearTimeout(timeout); } reject(abortError); }; const resolveHandler = () => { if (aborter !== undefined) { aborter.removeEventListener("abort", abortHandler); } resolve(); }; timeout = setTimeout(resolveHandler, timeInMs); if (aborter !== undefined) { aborter.addEventListener("abort", abortHandler); } }); } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /* * We need to imitate .Net culture-aware sorting, which is used in storage service. * Below tables contain sort-keys for en-US culture. */ const table_lv0 = new Uint32Array([ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71c, 0x0, 0x71f, 0x721, 0x723, 0x725, 0x0, 0x0, 0x0, 0x72d, 0x803, 0x0, 0x0, 0x733, 0x0, 0xd03, 0xd1a, 0xd1c, 0xd1e, 0xd20, 0xd22, 0xd24, 0xd26, 0xd28, 0xd2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe02, 0xe09, 0xe0a, 0xe1a, 0xe21, 0xe23, 0xe25, 0xe2c, 0xe32, 0xe35, 0xe36, 0xe48, 0xe51, 0xe70, 0xe7c, 0xe7e, 0xe89, 0xe8a, 0xe91, 0xe99, 0xe9f, 0xea2, 0xea4, 0xea6, 0xea7, 0xea9, 0x0, 0x0, 0x0, 0x743, 0x744, 0x748, 0xe02, 0xe09, 0xe0a, 0xe1a, 0xe21, 0xe23, 0xe25, 0xe2c, 0xe32, 0xe35, 0xe36, 0xe48, 0xe51, 0xe70, 0xe7c, 0xe7e, 0xe89, 0xe8a, 0xe91, 0xe99, 0xe9f, 0xea2, 0xea4, 0xea6, 0xea7, 0xea9, 0x0, 0x74c, 0x0, 0x750, 0x0, ]); const table_lv2 = new Uint32Array([ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ]); const table_lv4 = new Uint32Array([ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8212, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ]); function compareHeader(lhs, rhs) { if (isLessThan(lhs, rhs)) return -1; return 1; } function isLessThan(lhs, rhs) { const tables = [table_lv0, table_lv2, table_lv4]; let curr_level = 0; let i = 0; let j = 0; while (curr_level < tables.length) { if (curr_level === tables.length - 1 && i !== j) { return i > j; } const weight1 = i < lhs.length ? tables[curr_level][lhs[i].charCodeAt(0)] : 0x1; const weight2 = j < rhs.length ? tables[curr_level][rhs[j].charCodeAt(0)] : 0x1; if (weight1 === 0x1 && weight2 === 0x1) { i = 0; j = 0; ++curr_level; } else if (weight1 === weight2) { ++i; ++j; } else if (weight1 === 0) { ++i; } else if (weight2 === 0) { ++j; } else { return weight1 < weight2; } } return false; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * StorageSharedKeyCredentialPolicy is a policy used to sign HTTP request with a shared key. */ class StorageSharedKeyCredentialPolicy extends CredentialPolicy { /** * Reference to StorageSharedKeyCredential which generates StorageSharedKeyCredentialPolicy */ factory; /** * Creates an instance of StorageSharedKeyCredentialPolicy. * @param nextPolicy - * @param options - * @param factory - */ constructor(nextPolicy, options, factory) { super(nextPolicy, options); this.factory = factory; } /** * Signs request. * * @param request - */ signRequest(request) { request.headers.set(HeaderConstants.X_MS_DATE, new Date().toUTCString()); if (request.body && (typeof request.body === "string" || request.body !== undefined) && request.body.length > 0) { request.headers.set(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(request.body)); } const stringToSign = [ request.method.toUpperCase(), this.getHeaderValueToSign(request, HeaderConstants.CONTENT_LANGUAGE), this.getHeaderValueToSign(request, HeaderConstants.CONTENT_ENCODING), this.getHeaderValueToSign(request, HeaderConstants.CONTENT_LENGTH), this.getHeaderValueToSign(request, HeaderConstants.CONTENT_MD5), this.getHeaderValueToSign(request, HeaderConstants.CONTENT_TYPE), this.getHeaderValueToSign(request, HeaderConstants.DATE), this.getHeaderValueToSign(request, HeaderConstants.IF_MODIFIED_SINCE), this.getHeaderValueToSign(request, HeaderConstants.IF_MATCH), this.getHeaderValueToSign(request, HeaderConstants.IF_NONE_MATCH), this.getHeaderValueToSign(request, HeaderConstants.IF_UNMODIFIED_SINCE), this.getHeaderValueToSign(request, HeaderConstants.RANGE), ].join("\n") + "\n" + this.getCanonicalizedHeadersString(request) + this.getCanonicalizedResourceString(request); const signature = this.factory.computeHMACSHA256(stringToSign); request.headers.set(HeaderConstants.AUTHORIZATION, `SharedKey ${this.factory.accountName}:${signature}`); // console.log(`[URL]:${request.url}`); // console.log(`[HEADERS]:${request.headers.toString()}`); // console.log(`[STRING TO SIGN]:${JSON.stringify(stringToSign)}`); // console.log(`[KEY]: ${request.headers.get(HeaderConstants.AUTHORIZATION)}`); return request; } /** * Retrieve header value according to shared key sign rules. * @see https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key * * @param request - * @param headerName - */ getHeaderValueToSign(request, headerName) { const value = request.headers.get(headerName); if (!value) { return ""; } // When using version 2015-02-21 or later, if Content-Length is zero, then // set the Content-Length part of the StringToSign to an empty string. // https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key if (headerName === HeaderConstants.CONTENT_LENGTH && value === "0") { return ""; } return value; } /** * To construct the CanonicalizedHeaders portion of the signature string, follow these steps: * 1. Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header. * 2. Convert each HTTP header name to lowercase. * 3. Sort the headers lexicographically by header name, in ascending order. * Each header may appear only once in the string. * 4. Replace any linear whitespace in the header value with a single space. * 5. Trim any whitespace around the colon in the header. * 6. Finally, append a new-line character to each canonicalized header in the resulting list. * Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string. * * @param request - */ getCanonicalizedHeadersString(request) { let headersArray = request.headers.headersArray().filter((value) => { return value.name.toLowerCase().startsWith(HeaderConstants.PREFIX_FOR_STORAGE); }); headersArray.sort((a, b) => { return compareHeader(a.name.toLowerCase(), b.name.toLowerCase()); }); // Remove duplicate headers headersArray = headersArray.filter((value, index, array) => { if (index > 0 && value.name.toLowerCase() === array[index - 1].name.toLowerCase()) { return false; } return true; }); let canonicalizedHeadersStringToSign = ""; headersArray.forEach((header) => { canonicalizedHeadersStringToSign += `${header.name .toLowerCase() .trimRight()}:${header.value.trimLeft()}\n`; }); return canonicalizedHeadersStringToSign; } /** * Retrieves the webResource canonicalized resource string. * * @param request - */ getCanonicalizedResourceString(request) { const path = getURLPath(request.url) || "/"; let canonicalizedResourceString = ""; canonicalizedResourceString += `/${this.factory.accountName}${path}`; const queries = getURLQueries(request.url); const lowercaseQueries = {}; if (queries) { const queryKeys = []; for (const key in queries) { if (Object.prototype.hasOwnProperty.call(queries, key)) { const lowercaseKey = key.toLowerCase(); lowercaseQueries[lowercaseKey] = queries[key]; queryKeys.push(lowercaseKey); } } queryKeys.sort(); for (const key of queryKeys) { canonicalizedResourceString += `\n${key}:${decodeURIComponent(lowercaseQueries[key])}`; } } return canonicalizedResourceString; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * StorageSharedKeyCredential for account key authorization of Azure Storage service. */ class StorageSharedKeyCredential extends Credential { /** * Azure Storage account name; readonly. */ accountName; /** * Azure Storage account key; readonly. */ accountKey; /** * Creates an instance of StorageSharedKeyCredential. * @param accountName - * @param accountKey - */ constructor(accountName, accountKey) { super(); this.accountName = accountName; this.accountKey = Buffer.from(accountKey, "base64"); } /** * Creates a StorageSharedKeyCredentialPolicy object. * * @param nextPolicy - * @param options - */ create(nextPolicy, options) { return new StorageSharedKeyCredentialPolicy(nextPolicy, options, this); } /** * Generates a hash signature for an HTTP request or for a SAS. * * @param stringToSign - */ computeHMACSHA256(stringToSign) { return createHmac("sha256", this.accountKey).update(stringToSign, "utf8").digest("base64"); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The `@azure/logger` configuration for this package. */ const logger = createClientLogger("storage-common"); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * RetryPolicy types. */ var StorageRetryPolicyType; (function (StorageRetryPolicyType) { /** * Exponential retry. Retry time delay grows exponentially. */ StorageRetryPolicyType[StorageRetryPolicyType["EXPONENTIAL"] = 0] = "EXPONENTIAL"; /** * Linear retry. Retry time delay grows linearly. */ StorageRetryPolicyType[StorageRetryPolicyType["FIXED"] = 1] = "FIXED"; })(StorageRetryPolicyType || (StorageRetryPolicyType = {})); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // Default values of StorageRetryOptions const DEFAULT_RETRY_OPTIONS$1 = { maxRetryDelayInMs: 120 * 1000, maxTries: 4, retryDelayInMs: 4 * 1000, retryPolicyType: StorageRetryPolicyType.EXPONENTIAL, secondaryHost: "", tryTimeoutInMs: undefined, // Use server side default timeout strategy }; const RETRY_ABORT_ERROR$1 = new AbortError$1("The operation was aborted."); /** * Retry policy with exponential retry and linear retry implemented. */ class StorageRetryPolicy extends BaseRequestPolicy { /** * RetryOptions. */ retryOptions; /** * Creates an instance of RetryPolicy. * * @param nextPolicy - * @param options - * @param retryOptions - */ constructor(nextPolicy, options, retryOptions = DEFAULT_RETRY_OPTIONS$1) { super(nextPolicy, options); // Initialize retry options this.retryOptions = { retryPolicyType: retryOptions.retryPolicyType ? retryOptions.retryPolicyType : DEFAULT_RETRY_OPTIONS$1.retryPolicyType, maxTries: retryOptions.maxTries && retryOptions.maxTries >= 1 ? Math.floor(retryOptions.maxTries) : DEFAULT_RETRY_OPTIONS$1.maxTries, tryTimeoutInMs: retryOptions.tryTimeoutInMs && retryOptions.tryTimeoutInMs >= 0 ? retryOptions.tryTimeoutInMs : DEFAULT_RETRY_OPTIONS$1.tryTimeoutInMs, retryDelayInMs: retryOptions.retryDelayInMs && retryOptions.retryDelayInMs >= 0 ? Math.min(retryOptions.retryDelayInMs, retryOptions.maxRetryDelayInMs ? retryOptions.maxRetryDelayInMs : DEFAULT_RETRY_OPTIONS$1.maxRetryDelayInMs) : DEFAULT_RETRY_OPTIONS$1.retryDelayInMs, maxRetryDelayInMs: retryOptions.maxRetryDelayInMs && retryOptions.maxRetryDelayInMs >= 0 ? retryOptions.maxRetryDelayInMs : DEFAULT_RETRY_OPTIONS$1.maxRetryDelayInMs, secondaryHost: retryOptions.secondaryHost ? retryOptions.secondaryHost : DEFAULT_RETRY_OPTIONS$1.secondaryHost, }; } /** * Sends request. * * @param request - */ async sendRequest(request) { return this.attemptSendRequest(request, false, 1); } /** * Decide and perform next retry. Won't mutate request parameter. * * @param request - * @param secondaryHas404 - If attempt was against the secondary & it returned a StatusNotFound (404), then * the resource was not found. This may be due to replication delay. So, in this * case, we'll never try the secondary again for this operation. * @param attempt - How many retries has been attempted to performed, starting from 1, which includes * the attempt will be performed by this method call. */ async attemptSendRequest(request, secondaryHas404, attempt) { const newRequest = request.clone(); const isPrimaryRetry = secondaryHas404 || !this.retryOptions.secondaryHost || !(request.method === "GET" || request.method === "HEAD" || request.method === "OPTIONS") || attempt % 2 === 1; if (!isPrimaryRetry) { newRequest.url = setURLHost(newRequest.url, this.retryOptions.secondaryHost); } // Set the server-side timeout query parameter "timeout=[seconds]" if (this.retryOptions.tryTimeoutInMs) { newRequest.url = setURLParameter$1(newRequest.url, URLConstants$1.Parameters.TIMEOUT, Math.floor(this.retryOptions.tryTimeoutInMs / 1000).toString()); } let response; try { logger.info(`RetryPolicy: =====> Try=${attempt} ${isPrimaryRetry ? "Primary" : "Secondary"}`); response = await this._nextPolicy.sendRequest(newRequest); if (!this.shouldRetry(isPrimaryRetry, attempt, response)) { return response; } secondaryHas404 = secondaryHas404 || (!isPrimaryRetry && response.status === 404); } catch (err) { logger.error(`RetryPolicy: Caught error, message: ${err.message}, code: ${err.code}`); if (!this.shouldRetry(isPrimaryRetry, attempt, response, err)) { throw err; } } await this.delay(isPrimaryRetry, attempt, request.abortSignal); return this.attemptSendRequest(request, secondaryHas404, ++attempt); } /** * Decide whether to retry according to last HTTP response and retry counters. * * @param isPrimaryRetry - * @param attempt - * @param response - * @param err - */ shouldRetry(isPrimaryRetry, attempt, response, err) { if (attempt >= this.retryOptions.maxTries) { logger.info(`RetryPolicy: Attempt(s) ${attempt} >= maxTries ${this.retryOptions .maxTries}, no further try.`); return false; } // Handle network failures, you may need to customize the list when you implement // your own http client const retriableErrors = [ "ETIMEDOUT", "ESOCKETTIMEDOUT", "ECONNREFUSED", "ECONNRESET", "ENOENT", "ENOTFOUND", "TIMEOUT", "EPIPE", "REQUEST_SEND_ERROR", // For default xhr based http client provided in ms-rest-js ]; if (err) { for (const retriableError of retriableErrors) { if (err.name.toUpperCase().includes(retriableError) || err.message.toUpperCase().includes(retriableError) || (err.code && err.code.toString().toUpperCase() === retriableError)) { logger.info(`RetryPolicy: Network error ${retriableError} found, will retry.`); return true; } } } // If attempt was against the secondary & it returned a StatusNotFound (404), then // the resource was not found. This may be due to replication delay. So, in this // case, we'll never try the secondary again for this operation. if (response || err) { const statusCode = response ? response.status : err ? err.statusCode : 0; if (!isPrimaryRetry && statusCode === 404) { logger.info(`RetryPolicy: Secondary access with 404, will retry.`); return true; } // Server internal error or server timeout if (statusCode === 503 || statusCode === 500) { logger.info(`RetryPolicy: Will retry for status code ${statusCode}.`); return true; } } if (response) { // Retry select Copy Source Error Codes. if (response?.status >= 400) { const copySourceError = response.headers.get(HeaderConstants.X_MS_CopySourceErrorCode); if (copySourceError !== undefined) { switch (copySourceError) { case "InternalError": case "OperationTimedOut": case "ServerBusy": return true; } } } } if (err?.code === "PARSE_ERROR" && err?.message.startsWith(`Error "Error: Unclosed root tag`)) { logger.info("RetryPolicy: Incomplete XML response likely due to service timeout, will retry."); return true; } return false; } /** * Delay a calculated time between retries. * * @param isPrimaryRetry - * @param attempt - * @param abortSignal - */ async delay(isPrimaryRetry, attempt, abortSignal) { let delayTimeInMs = 0; if (isPrimaryRetry) { switch (this.retryOptions.retryPolicyType) { case StorageRetryPolicyType.EXPONENTIAL: delayTimeInMs = Math.min((Math.pow(2, attempt - 1) - 1) * this.retryOptions.retryDelayInMs, this.retryOptions.maxRetryDelayInMs); break; case StorageRetryPolicyType.FIXED: delayTimeInMs = this.retryOptions.retryDelayInMs; break; } } else { delayTimeInMs = Math.random() * 1000; } logger.info(`RetryPolicy: Delay for ${delayTimeInMs}ms`); return delay(delayTimeInMs, abortSignal, RETRY_ABORT_ERROR$1); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * StorageRetryPolicyFactory is a factory class helping generating {@link StorageRetryPolicy} objects. */ class StorageRetryPolicyFactory { retryOptions; /** * Creates an instance of StorageRetryPolicyFactory. * @param retryOptions - */ constructor(retryOptions) { this.retryOptions = retryOptions; } /** * Creates a StorageRetryPolicy object. * * @param nextPolicy - * @param options - */ create(nextPolicy, options) { return new StorageRetryPolicy(nextPolicy, options, this.retryOptions); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the StorageBrowserPolicy. */ const storageBrowserPolicyName = "storageBrowserPolicy"; /** * storageBrowserPolicy is a policy used to prevent browsers from caching requests * and to remove cookies and explicit content-length headers. * * In Node.js, this policy is a no-op pass-through. */ function storageBrowserPolicy() { return { name: storageBrowserPolicyName, async sendRequest(request, next) { return next(request); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the storageCorrectContentLengthPolicy. */ const storageCorrectContentLengthPolicyName = "StorageCorrectContentLengthPolicy"; /** * storageCorrectContentLengthPolicy to correctly set Content-Length header with request body length. */ function storageCorrectContentLengthPolicy() { function correctContentLength(request) { if (request.body && (typeof request.body === "string" || Buffer.isBuffer(request.body)) && request.body.length > 0) { request.headers.set(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(request.body)); } } return { name: storageCorrectContentLengthPolicyName, async sendRequest(request, next) { correctContentLength(request); return next(request); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Name of the {@link storageRetryPolicy} */ const storageRetryPolicyName = "storageRetryPolicy"; // Default values of StorageRetryOptions const DEFAULT_RETRY_OPTIONS = { maxRetryDelayInMs: 120 * 1000, maxTries: 4, retryDelayInMs: 4 * 1000, retryPolicyType: StorageRetryPolicyType.EXPONENTIAL, secondaryHost: "", tryTimeoutInMs: undefined, // Use server side default timeout strategy }; const retriableErrors = [ "ETIMEDOUT", "ESOCKETTIMEDOUT", "ECONNREFUSED", "ECONNRESET", "ENOENT", "ENOTFOUND", "TIMEOUT", "EPIPE", "REQUEST_SEND_ERROR", ]; const RETRY_ABORT_ERROR = new AbortError$1("The operation was aborted."); /** * Retry policy with exponential retry and linear retry implemented. */ function storageRetryPolicy(options = {}) { const retryPolicyType = options.retryPolicyType ?? DEFAULT_RETRY_OPTIONS.retryPolicyType; const maxTries = options.maxTries ?? DEFAULT_RETRY_OPTIONS.maxTries; const retryDelayInMs = options.retryDelayInMs ?? DEFAULT_RETRY_OPTIONS.retryDelayInMs; const maxRetryDelayInMs = options.maxRetryDelayInMs ?? DEFAULT_RETRY_OPTIONS.maxRetryDelayInMs; const secondaryHost = options.secondaryHost ?? DEFAULT_RETRY_OPTIONS.secondaryHost; const tryTimeoutInMs = options.tryTimeoutInMs ?? DEFAULT_RETRY_OPTIONS.tryTimeoutInMs; function shouldRetry({ isPrimaryRetry, attempt, response, error, }) { if (attempt >= maxTries) { logger.info(`RetryPolicy: Attempt(s) ${attempt} >= maxTries ${maxTries}, no further try.`); return false; } if (error) { for (const retriableError of retriableErrors) { if (error.name.toUpperCase().includes(retriableError) || error.message.toUpperCase().includes(retriableError) || (error.code && error.code.toString().toUpperCase() === retriableError)) { logger.info(`RetryPolicy: Network error ${retriableError} found, will retry.`); return true; } } if (error?.code === "PARSE_ERROR" && error?.message.startsWith(`Error "Error: Unclosed root tag`)) { logger.info("RetryPolicy: Incomplete XML response likely due to service timeout, will retry."); return true; } } // If attempt was against the secondary & it returned a StatusNotFound (404), then // the resource was not found. This may be due to replication delay. So, in this // case, we'll never try the secondary again for this operation. if (response || error) { const statusCode = response?.status ?? error?.statusCode ?? 0; if (!isPrimaryRetry && statusCode === 404) { logger.info(`RetryPolicy: Secondary access with 404, will retry.`); return true; } // Server internal error or server timeout if (statusCode === 503 || statusCode === 500) { logger.info(`RetryPolicy: Will retry for status code ${statusCode}.`); return true; } } if (response) { // Retry select Copy Source Error Codes. if (response?.status >= 400) { const copySourceError = response.headers.get(HeaderConstants.X_MS_CopySourceErrorCode); if (copySourceError !== undefined) { switch (copySourceError) { case "InternalError": case "OperationTimedOut": case "ServerBusy": return true; } } } } return false; } function calculateDelay(isPrimaryRetry, attempt) { let delayTimeInMs = 0; if (isPrimaryRetry) { switch (retryPolicyType) { case StorageRetryPolicyType.EXPONENTIAL: delayTimeInMs = Math.min((Math.pow(2, attempt - 1) - 1) * retryDelayInMs, maxRetryDelayInMs); break; case StorageRetryPolicyType.FIXED: delayTimeInMs = retryDelayInMs; break; } } else { delayTimeInMs = Math.random() * 1000; } logger.info(`RetryPolicy: Delay for ${delayTimeInMs}ms`); return delayTimeInMs; } return { name: storageRetryPolicyName, async sendRequest(request, next) { // Set the server-side timeout query parameter "timeout=[seconds]" if (tryTimeoutInMs) { request.url = setURLParameter$1(request.url, URLConstants$1.Parameters.TIMEOUT, String(Math.floor(tryTimeoutInMs / 1000))); } const primaryUrl = request.url; const secondaryUrl = secondaryHost ? setURLHost(request.url, secondaryHost) : undefined; let secondaryHas404 = false; let attempt = 1; let retryAgain = true; let response; let error; while (retryAgain) { const isPrimaryRetry = secondaryHas404 || !secondaryUrl || !["GET", "HEAD", "OPTIONS"].includes(request.method) || attempt % 2 === 1; request.url = isPrimaryRetry ? primaryUrl : secondaryUrl; response = undefined; error = undefined; try { logger.info(`RetryPolicy: =====> Try=${attempt} ${isPrimaryRetry ? "Primary" : "Secondary"}`); response = await next(request); secondaryHas404 = secondaryHas404 || (!isPrimaryRetry && response.status === 404); } catch (e) { if (isRestError(e)) { logger.error(`RetryPolicy: Caught error, message: ${e.message}, code: ${e.code}`); error = e; } else { logger.error(`RetryPolicy: Caught error, message: ${getErrorMessage(e)}`); throw e; } } retryAgain = shouldRetry({ isPrimaryRetry, attempt, response, error }); if (retryAgain) { await delay(calculateDelay(isPrimaryRetry, attempt), request.abortSignal, RETRY_ABORT_ERROR); } attempt++; } if (response) { return response; } throw error ?? new RestError("RetryPolicy failed without known error."); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the storageSharedKeyCredentialPolicy. */ const storageSharedKeyCredentialPolicyName = "storageSharedKeyCredentialPolicy"; /** * storageSharedKeyCredentialPolicy handles signing requests using storage account keys. */ function storageSharedKeyCredentialPolicy(options) { function signRequest(request) { request.headers.set(HeaderConstants.X_MS_DATE, new Date().toUTCString()); if (request.body && (typeof request.body === "string" || Buffer.isBuffer(request.body)) && request.body.length > 0) { request.headers.set(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(request.body)); } const stringToSign = [ request.method.toUpperCase(), getHeaderValueToSign(request, HeaderConstants.CONTENT_LANGUAGE), getHeaderValueToSign(request, HeaderConstants.CONTENT_ENCODING), getHeaderValueToSign(request, HeaderConstants.CONTENT_LENGTH), getHeaderValueToSign(request, HeaderConstants.CONTENT_MD5), getHeaderValueToSign(request, HeaderConstants.CONTENT_TYPE), getHeaderValueToSign(request, HeaderConstants.DATE), getHeaderValueToSign(request, HeaderConstants.IF_MODIFIED_SINCE), getHeaderValueToSign(request, HeaderConstants.IF_MATCH), getHeaderValueToSign(request, HeaderConstants.IF_NONE_MATCH), getHeaderValueToSign(request, HeaderConstants.IF_UNMODIFIED_SINCE), getHeaderValueToSign(request, HeaderConstants.RANGE), ].join("\n") + "\n" + getCanonicalizedHeadersString(request) + getCanonicalizedResourceString(request); const signature = createHmac("sha256", options.accountKey) .update(stringToSign, "utf8") .digest("base64"); request.headers.set(HeaderConstants.AUTHORIZATION, `SharedKey ${options.accountName}:${signature}`); // console.log(`[URL]:${request.url}`); // console.log(`[HEADERS]:${request.headers.toString()}`); // console.log(`[STRING TO SIGN]:${JSON.stringify(stringToSign)}`); // console.log(`[KEY]: ${request.headers.get(HeaderConstants.AUTHORIZATION)}`); } /** * Retrieve header value according to shared key sign rules. * @see https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key */ function getHeaderValueToSign(request, headerName) { const value = request.headers.get(headerName); if (!value) { return ""; } // When using version 2015-02-21 or later, if Content-Length is zero, then // set the Content-Length part of the StringToSign to an empty string. // https://learn.microsoft.com/rest/api/storageservices/authenticate-with-shared-key if (headerName === HeaderConstants.CONTENT_LENGTH && value === "0") { return ""; } return value; } /** * To construct the CanonicalizedHeaders portion of the signature string, follow these steps: * 1. Retrieve all headers for the resource that begin with x-ms-, including the x-ms-date header. * 2. Convert each HTTP header name to lowercase. * 3. Sort the headers lexicographically by header name, in ascending order. * Each header may appear only once in the string. * 4. Replace any linear whitespace in the header value with a single space. * 5. Trim any whitespace around the colon in the header. * 6. Finally, append a new-line character to each canonicalized header in the resulting list. * Construct the CanonicalizedHeaders string by concatenating all headers in this list into a single string. * */ function getCanonicalizedHeadersString(request) { let headersArray = []; for (const [name, value] of request.headers) { if (name.toLowerCase().startsWith(HeaderConstants.PREFIX_FOR_STORAGE)) { headersArray.push({ name, value }); } } headersArray.sort((a, b) => { return compareHeader(a.name.toLowerCase(), b.name.toLowerCase()); }); // Remove duplicate headers headersArray = headersArray.filter((value, index, array) => { if (index > 0 && value.name.toLowerCase() === array[index - 1].name.toLowerCase()) { return false; } return true; }); let canonicalizedHeadersStringToSign = ""; headersArray.forEach((header) => { canonicalizedHeadersStringToSign += `${header.name .toLowerCase() .trimRight()}:${header.value.trimLeft()}\n`; }); return canonicalizedHeadersStringToSign; } function getCanonicalizedResourceString(request) { const path = getURLPath(request.url) || "/"; let canonicalizedResourceString = ""; canonicalizedResourceString += `/${options.accountName}${path}`; const queries = getURLQueries(request.url); const lowercaseQueries = {}; if (queries) { const queryKeys = []; for (const key in queries) { if (Object.prototype.hasOwnProperty.call(queries, key)) { const lowercaseKey = key.toLowerCase(); lowercaseQueries[lowercaseKey] = queries[key]; queryKeys.push(lowercaseKey); } } queryKeys.sort(); for (const key of queryKeys) { canonicalizedResourceString += `\n${key}:${decodeURIComponent(lowercaseQueries[key])}`; } } return canonicalizedResourceString; } return { name: storageSharedKeyCredentialPolicyName, async sendRequest(request, next) { signRequest(request); return next(request); }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * The programmatic identifier of the StorageRequestFailureDetailsParserPolicy. */ const storageRequestFailureDetailsParserPolicyName = "storageRequestFailureDetailsParserPolicy"; /** * StorageRequestFailureDetailsParserPolicy */ function storageRequestFailureDetailsParserPolicy() { return { name: storageRequestFailureDetailsParserPolicyName, async sendRequest(request, next) { try { const response = await next(request); return response; } catch (err) { if (typeof err === "object" && err !== null && err.response && err.response.parsedBody) { if (err.response.parsedBody.code === "InvalidHeaderValue" && err.response.parsedBody.HeaderName === "x-ms-version") { err.message = "The provided service version is not enabled on this storage account. Please see https://learn.microsoft.com/rest/api/storageservices/versioning-for-the-azure-storage-services for additional information.\n"; } } throw err; } }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * UserDelegationKeyCredential is only used for generation of user delegation SAS. * @see https://learn.microsoft.com/rest/api/storageservices/create-user-delegation-sas */ class UserDelegationKeyCredential { /** * Azure Storage account name; readonly. */ accountName; /** * Azure Storage user delegation key; readonly. */ userDelegationKey; /** * Key value in Buffer type. */ key; /** * Creates an instance of UserDelegationKeyCredential. * @param accountName - * @param userDelegationKey - */ constructor(accountName, userDelegationKey) { this.accountName = accountName; this.userDelegationKey = userDelegationKey; this.key = Buffer.from(userDelegationKey.value, "base64"); } /** * Generates a hash signature for an HTTP request or for a SAS. * * @param stringToSign - */ computeHMACSHA256(stringToSign) { return createHmac("sha256", this.key).update(stringToSign, "utf8").digest("base64"); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const SDK_VERSION = "12.32.0"; const SERVICE_VERSION = "2026-04-06"; const BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES = 256 * 1024 * 1024; // 256MB const BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES = 4000 * 1024 * 1024; // 4000MB const BLOCK_BLOB_MAX_BLOCKS = 50000; const DEFAULT_BLOCK_BUFFER_SIZE_BYTES = 8 * 1024 * 1024; // 8MB const DEFAULT_BLOB_DOWNLOAD_BLOCK_BYTES = 4 * 1024 * 1024; // 4MB const DEFAULT_MAX_DOWNLOAD_RETRY_REQUESTS = 5; const REQUEST_TIMEOUT = 100 * 1000; // In ms /** * The OAuth scope to use with Azure Storage. */ const StorageOAuthScopes = "https://storage.azure.com/.default"; const URLConstants = { Parameters: { SNAPSHOT: "snapshot", VERSIONID: "versionid"}, }; const ETagNone = ""; const ETagAny = "*"; const EncryptionAlgorithmAES25 = "AES256"; const DevelopmentConnectionString = `DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;`; const StorageBlobLoggingAllowedHeaderNames = [ "Access-Control-Allow-Origin", "Cache-Control", "Content-Length", "Content-Type", "Date", "Request-Id", "traceparent", "Transfer-Encoding", "User-Agent", "x-ms-client-request-id", "x-ms-date", "x-ms-error-code", "x-ms-request-id", "x-ms-return-client-request-id", "x-ms-version", "Accept-Ranges", "Content-Disposition", "Content-Encoding", "Content-Language", "Content-MD5", "Content-Range", "ETag", "Last-Modified", "Server", "Vary", "x-ms-content-crc64", "x-ms-copy-action", "x-ms-copy-completion-time", "x-ms-copy-id", "x-ms-copy-progress", "x-ms-copy-status", "x-ms-has-immutability-policy", "x-ms-has-legal-hold", "x-ms-lease-state", "x-ms-lease-status", "x-ms-range", "x-ms-request-server-encrypted", "x-ms-server-encrypted", "x-ms-snapshot", "x-ms-source-range", "If-Match", "If-Modified-Since", "If-None-Match", "If-Unmodified-Since", "x-ms-access-tier", "x-ms-access-tier-change-time", "x-ms-access-tier-inferred", "x-ms-account-kind", "x-ms-archive-status", "x-ms-blob-append-offset", "x-ms-blob-cache-control", "x-ms-blob-committed-block-count", "x-ms-blob-condition-appendpos", "x-ms-blob-condition-maxsize", "x-ms-blob-content-disposition", "x-ms-blob-content-encoding", "x-ms-blob-content-language", "x-ms-blob-content-length", "x-ms-blob-content-md5", "x-ms-blob-content-type", "x-ms-blob-public-access", "x-ms-blob-sequence-number", "x-ms-blob-type", "x-ms-copy-destination-snapshot", "x-ms-creation-time", "x-ms-default-encryption-scope", "x-ms-delete-snapshots", "x-ms-delete-type-permanent", "x-ms-deny-encryption-scope-override", "x-ms-encryption-algorithm", "x-ms-if-sequence-number-eq", "x-ms-if-sequence-number-le", "x-ms-if-sequence-number-lt", "x-ms-incremental-copy", "x-ms-lease-action", "x-ms-lease-break-period", "x-ms-lease-duration", "x-ms-lease-id", "x-ms-lease-time", "x-ms-page-write", "x-ms-proposed-lease-id", "x-ms-range-get-content-md5", "x-ms-rehydrate-priority", "x-ms-sequence-number-action", "x-ms-sku-name", "x-ms-source-content-md5", "x-ms-source-if-match", "x-ms-source-if-modified-since", "x-ms-source-if-none-match", "x-ms-source-if-unmodified-since", "x-ms-tag-count", "x-ms-encryption-key-sha256", "x-ms-copy-source-error-code", "x-ms-copy-source-status-code", "x-ms-if-tags", "x-ms-source-if-tags", ]; const StorageBlobLoggingAllowedQueryParameters = [ "comp", "maxresults", "rscc", "rscd", "rsce", "rscl", "rsct", "se", "si", "sip", "sp", "spr", "sr", "srt", "ss", "st", "sv", "include", "marker", "prefix", "copyid", "restype", "blockid", "blocklisttype", "delimiter", "prevsnapshot", "ske", "skoid", "sks", "skt", "sktid", "skv", "snapshot", ]; const BlobUsesCustomerSpecifiedEncryptionMsg = "BlobUsesCustomerSpecifiedEncryption"; const BlobDoesNotUseCustomerSpecifiedEncryption = "BlobDoesNotUseCustomerSpecifiedEncryption"; /// List of ports used for path style addressing. /// Path style addressing means that storage account is put in URI's Path segment in instead of in host. const PathStylePorts = [ "10000", "10001", "10002", "10003", "10004", "10100", "10101", "10102", "10103", "10104", "11000", "11001", "11002", "11003", "11004", "11100", "11101", "11102", "11103", "11104", ]; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A helper to decide if a given argument satisfies the Pipeline contract * @param pipeline - An argument that may be a Pipeline * @returns true when the argument satisfies the Pipeline contract */ function isPipelineLike(pipeline) { if (!pipeline || typeof pipeline !== "object") { return false; } const castPipeline = pipeline; return (Array.isArray(castPipeline.factories) && typeof castPipeline.options === "object" && typeof castPipeline.toServiceClientOptions === "function"); } /** * A Pipeline class containing HTTP request policies. * You can create a default Pipeline by calling {@link newPipeline}. * Or you can create a Pipeline with your own policies by the constructor of Pipeline. * * Refer to {@link newPipeline} and provided policies before implementing your * customized Pipeline. */ class Pipeline { /** * A list of chained request policy factories. */ factories; /** * Configures pipeline logger and HTTP client. */ options; /** * Creates an instance of Pipeline. Customize HTTPClient by implementing IHttpClient interface. * * @param factories - * @param options - */ constructor(factories, options = {}) { this.factories = factories; this.options = options; } /** * Transfer Pipeline object to ServiceClientOptions object which is required by * ServiceClient constructor. * * @returns The ServiceClientOptions object from this Pipeline. */ toServiceClientOptions() { return { httpClient: this.options.httpClient, requestPolicyFactories: this.factories, }; } } /** * Creates a new Pipeline object with Credential provided. * * @param credential - Such as AnonymousCredential, StorageSharedKeyCredential or any credential from the `@azure/identity` package to authenticate requests to the service. You can also provide an object that implements the TokenCredential interface. If not specified, AnonymousCredential is used. * @param pipelineOptions - Optional. Options. * @returns A new Pipeline object. */ function newPipeline(credential, pipelineOptions = {}) { if (!credential) { credential = new AnonymousCredential(); } const pipeline = new Pipeline([], pipelineOptions); pipeline._credential = credential; return pipeline; } function processDownlevelPipeline(pipeline) { const knownFactoryFunctions = [ isAnonymousCredential, isStorageSharedKeyCredential, isCoreHttpBearerTokenFactory, isStorageBrowserPolicyFactory, isStorageRetryPolicyFactory, isStorageTelemetryPolicyFactory, isCoreHttpPolicyFactory, ]; if (pipeline.factories.length) { const novelFactories = pipeline.factories.filter((factory) => { return !knownFactoryFunctions.some((knownFactory) => knownFactory(factory)); }); if (novelFactories.length) { const hasInjector = novelFactories.some((factory) => isInjectorPolicyFactory(factory)); // if there are any left over, wrap in a requestPolicyFactoryPolicy return { wrappedPolicies: createRequestPolicyFactoryPolicy(novelFactories), afterRetry: hasInjector, }; } } return undefined; } function getCoreClientOptions(pipeline) { const { httpClient: v1Client, ...restOptions } = pipeline.options; let httpClient = pipeline._coreHttpClient; if (!httpClient) { httpClient = v1Client ? convertHttpClient(v1Client) : getCachedDefaultHttpClient(); pipeline._coreHttpClient = httpClient; } let corePipeline = pipeline._corePipeline; if (!corePipeline) { const packageDetails = `azsdk-js-azure-storage-blob/${SDK_VERSION}`; const userAgentPrefix = restOptions.userAgentOptions && restOptions.userAgentOptions.userAgentPrefix ? `${restOptions.userAgentOptions.userAgentPrefix} ${packageDetails}` : `${packageDetails}`; corePipeline = createClientPipeline({ ...restOptions, loggingOptions: { additionalAllowedHeaderNames: StorageBlobLoggingAllowedHeaderNames, additionalAllowedQueryParameters: StorageBlobLoggingAllowedQueryParameters, logger: logger$1.info, }, userAgentOptions: { userAgentPrefix, }, serializationOptions: { stringifyXML, serializerOptions: { xml: { // Use customized XML char key of "#" so we can deserialize metadata // with "_" key xmlCharKey: "#", }, }, }, deserializationOptions: { parseXML, serializerOptions: { xml: { // Use customized XML char key of "#" so we can deserialize metadata // with "_" key xmlCharKey: "#", }, }, }, }); corePipeline.removePolicy({ phase: "Retry" }); corePipeline.removePolicy({ name: decompressResponsePolicyName }); corePipeline.addPolicy(storageCorrectContentLengthPolicy()); corePipeline.addPolicy(storageRetryPolicy(restOptions.retryOptions), { phase: "Retry" }); corePipeline.addPolicy(storageRequestFailureDetailsParserPolicy()); corePipeline.addPolicy(storageBrowserPolicy()); const downlevelResults = processDownlevelPipeline(pipeline); if (downlevelResults) { corePipeline.addPolicy(downlevelResults.wrappedPolicies, downlevelResults.afterRetry ? { afterPhase: "Retry" } : undefined); } const credential = getCredentialFromPipeline(pipeline); if (isTokenCredential(credential)) { corePipeline.addPolicy(bearerTokenAuthenticationPolicy({ credential, scopes: restOptions.audience ?? StorageOAuthScopes, challengeCallbacks: { authorizeRequestOnChallenge: authorizeRequestOnTenantChallenge }, }), { phase: "Sign" }); } else if (credential instanceof StorageSharedKeyCredential) { corePipeline.addPolicy(storageSharedKeyCredentialPolicy({ accountName: credential.accountName, accountKey: credential.accountKey, }), { phase: "Sign" }); } pipeline._corePipeline = corePipeline; } return { ...restOptions, allowInsecureConnection: true, httpClient, pipeline: corePipeline, }; } function getCredentialFromPipeline(pipeline) { // see if we squirreled one away on the type itself if (pipeline._credential) { return pipeline._credential; } // if it came from another package, loop over the factories and look for one like before let credential = new AnonymousCredential(); for (const factory of pipeline.factories) { if (isTokenCredential(factory.credential)) { // Only works if the factory has been attached a "credential" property. // We do that in newPipeline() when using TokenCredential. credential = factory.credential; } else if (isStorageSharedKeyCredential(factory)) { return factory; } } return credential; } function isStorageSharedKeyCredential(factory) { if (factory instanceof StorageSharedKeyCredential) { return true; } return factory.constructor.name === "StorageSharedKeyCredential"; } function isAnonymousCredential(factory) { if (factory instanceof AnonymousCredential) { return true; } return factory.constructor.name === "AnonymousCredential"; } function isCoreHttpBearerTokenFactory(factory) { return isTokenCredential(factory.credential); } function isStorageBrowserPolicyFactory(factory) { if (factory instanceof StorageBrowserPolicyFactory) { return true; } return factory.constructor.name === "StorageBrowserPolicyFactory"; } function isStorageRetryPolicyFactory(factory) { if (factory instanceof StorageRetryPolicyFactory) { return true; } return factory.constructor.name === "StorageRetryPolicyFactory"; } function isStorageTelemetryPolicyFactory(factory) { return factory.constructor.name === "TelemetryPolicyFactory"; } function isInjectorPolicyFactory(factory) { return factory.constructor.name === "InjectorPolicyFactory"; } function isCoreHttpPolicyFactory(factory) { const knownPolicies = [ "GenerateClientRequestIdPolicy", "TracingPolicy", "LogPolicy", "ProxyPolicy", "DisableResponseDecompressionPolicy", "KeepAlivePolicy", "DeserializationPolicy", ]; const mockHttpClient = { sendRequest: async (request) => { return { request, headers: request.headers.clone(), status: 500, }; }, }; const mockRequestPolicyOptions = { log(_logLevel, _message) { /* do nothing */ }, shouldLog(_logLevel) { return false; }, }; const policyInstance = factory.create(mockHttpClient, mockRequestPolicyOptions); const policyName = policyInstance.constructor.name; // bundlers sometimes add a custom suffix to the class name to make it unique return knownPolicies.some((knownPolicyName) => { return policyName.startsWith(knownPolicyName); }); } /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ /** Known values of {@link EncryptionAlgorithmType} that the service accepts. */ var KnownEncryptionAlgorithmType; (function (KnownEncryptionAlgorithmType) { /** AES256 */ KnownEncryptionAlgorithmType["AES256"] = "AES256"; })(KnownEncryptionAlgorithmType || (KnownEncryptionAlgorithmType = {})); /** Known values of {@link FileShareTokenIntent} that the service accepts. */ var KnownFileShareTokenIntent; (function (KnownFileShareTokenIntent) { /** Backup */ KnownFileShareTokenIntent["Backup"] = "backup"; })(KnownFileShareTokenIntent || (KnownFileShareTokenIntent = {})); /** Known values of {@link BlobExpiryOptions} that the service accepts. */ var KnownBlobExpiryOptions; (function (KnownBlobExpiryOptions) { /** NeverExpire */ KnownBlobExpiryOptions["NeverExpire"] = "NeverExpire"; /** RelativeToCreation */ KnownBlobExpiryOptions["RelativeToCreation"] = "RelativeToCreation"; /** RelativeToNow */ KnownBlobExpiryOptions["RelativeToNow"] = "RelativeToNow"; /** Absolute */ KnownBlobExpiryOptions["Absolute"] = "Absolute"; })(KnownBlobExpiryOptions || (KnownBlobExpiryOptions = {})); /** Known values of {@link StorageErrorCode} that the service accepts. */ var KnownStorageErrorCode; (function (KnownStorageErrorCode) { /** AccountAlreadyExists */ KnownStorageErrorCode["AccountAlreadyExists"] = "AccountAlreadyExists"; /** AccountBeingCreated */ KnownStorageErrorCode["AccountBeingCreated"] = "AccountBeingCreated"; /** AccountIsDisabled */ KnownStorageErrorCode["AccountIsDisabled"] = "AccountIsDisabled"; /** AuthenticationFailed */ KnownStorageErrorCode["AuthenticationFailed"] = "AuthenticationFailed"; /** AuthorizationFailure */ KnownStorageErrorCode["AuthorizationFailure"] = "AuthorizationFailure"; /** ConditionHeadersNotSupported */ KnownStorageErrorCode["ConditionHeadersNotSupported"] = "ConditionHeadersNotSupported"; /** ConditionNotMet */ KnownStorageErrorCode["ConditionNotMet"] = "ConditionNotMet"; /** EmptyMetadataKey */ KnownStorageErrorCode["EmptyMetadataKey"] = "EmptyMetadataKey"; /** InsufficientAccountPermissions */ KnownStorageErrorCode["InsufficientAccountPermissions"] = "InsufficientAccountPermissions"; /** InternalError */ KnownStorageErrorCode["InternalError"] = "InternalError"; /** InvalidAuthenticationInfo */ KnownStorageErrorCode["InvalidAuthenticationInfo"] = "InvalidAuthenticationInfo"; /** InvalidHeaderValue */ KnownStorageErrorCode["InvalidHeaderValue"] = "InvalidHeaderValue"; /** InvalidHttpVerb */ KnownStorageErrorCode["InvalidHttpVerb"] = "InvalidHttpVerb"; /** InvalidInput */ KnownStorageErrorCode["InvalidInput"] = "InvalidInput"; /** InvalidMd5 */ KnownStorageErrorCode["InvalidMd5"] = "InvalidMd5"; /** InvalidMetadata */ KnownStorageErrorCode["InvalidMetadata"] = "InvalidMetadata"; /** InvalidQueryParameterValue */ KnownStorageErrorCode["InvalidQueryParameterValue"] = "InvalidQueryParameterValue"; /** InvalidRange */ KnownStorageErrorCode["InvalidRange"] = "InvalidRange"; /** InvalidResourceName */ KnownStorageErrorCode["InvalidResourceName"] = "InvalidResourceName"; /** InvalidUri */ KnownStorageErrorCode["InvalidUri"] = "InvalidUri"; /** InvalidXmlDocument */ KnownStorageErrorCode["InvalidXmlDocument"] = "InvalidXmlDocument"; /** InvalidXmlNodeValue */ KnownStorageErrorCode["InvalidXmlNodeValue"] = "InvalidXmlNodeValue"; /** Md5Mismatch */ KnownStorageErrorCode["Md5Mismatch"] = "Md5Mismatch"; /** MetadataTooLarge */ KnownStorageErrorCode["MetadataTooLarge"] = "MetadataTooLarge"; /** MissingContentLengthHeader */ KnownStorageErrorCode["MissingContentLengthHeader"] = "MissingContentLengthHeader"; /** MissingRequiredQueryParameter */ KnownStorageErrorCode["MissingRequiredQueryParameter"] = "MissingRequiredQueryParameter"; /** MissingRequiredHeader */ KnownStorageErrorCode["MissingRequiredHeader"] = "MissingRequiredHeader"; /** MissingRequiredXmlNode */ KnownStorageErrorCode["MissingRequiredXmlNode"] = "MissingRequiredXmlNode"; /** MultipleConditionHeadersNotSupported */ KnownStorageErrorCode["MultipleConditionHeadersNotSupported"] = "MultipleConditionHeadersNotSupported"; /** OperationTimedOut */ KnownStorageErrorCode["OperationTimedOut"] = "OperationTimedOut"; /** OutOfRangeInput */ KnownStorageErrorCode["OutOfRangeInput"] = "OutOfRangeInput"; /** OutOfRangeQueryParameterValue */ KnownStorageErrorCode["OutOfRangeQueryParameterValue"] = "OutOfRangeQueryParameterValue"; /** RequestBodyTooLarge */ KnownStorageErrorCode["RequestBodyTooLarge"] = "RequestBodyTooLarge"; /** ResourceTypeMismatch */ KnownStorageErrorCode["ResourceTypeMismatch"] = "ResourceTypeMismatch"; /** RequestUrlFailedToParse */ KnownStorageErrorCode["RequestUrlFailedToParse"] = "RequestUrlFailedToParse"; /** ResourceAlreadyExists */ KnownStorageErrorCode["ResourceAlreadyExists"] = "ResourceAlreadyExists"; /** ResourceNotFound */ KnownStorageErrorCode["ResourceNotFound"] = "ResourceNotFound"; /** ServerBusy */ KnownStorageErrorCode["ServerBusy"] = "ServerBusy"; /** UnsupportedHeader */ KnownStorageErrorCode["UnsupportedHeader"] = "UnsupportedHeader"; /** UnsupportedXmlNode */ KnownStorageErrorCode["UnsupportedXmlNode"] = "UnsupportedXmlNode"; /** UnsupportedQueryParameter */ KnownStorageErrorCode["UnsupportedQueryParameter"] = "UnsupportedQueryParameter"; /** UnsupportedHttpVerb */ KnownStorageErrorCode["UnsupportedHttpVerb"] = "UnsupportedHttpVerb"; /** AppendPositionConditionNotMet */ KnownStorageErrorCode["AppendPositionConditionNotMet"] = "AppendPositionConditionNotMet"; /** BlobAlreadyExists */ KnownStorageErrorCode["BlobAlreadyExists"] = "BlobAlreadyExists"; /** BlobImmutableDueToPolicy */ KnownStorageErrorCode["BlobImmutableDueToPolicy"] = "BlobImmutableDueToPolicy"; /** BlobNotFound */ KnownStorageErrorCode["BlobNotFound"] = "BlobNotFound"; /** BlobOverwritten */ KnownStorageErrorCode["BlobOverwritten"] = "BlobOverwritten"; /** BlobTierInadequateForContentLength */ KnownStorageErrorCode["BlobTierInadequateForContentLength"] = "BlobTierInadequateForContentLength"; /** BlobUsesCustomerSpecifiedEncryption */ KnownStorageErrorCode["BlobUsesCustomerSpecifiedEncryption"] = "BlobUsesCustomerSpecifiedEncryption"; /** BlockCountExceedsLimit */ KnownStorageErrorCode["BlockCountExceedsLimit"] = "BlockCountExceedsLimit"; /** BlockListTooLong */ KnownStorageErrorCode["BlockListTooLong"] = "BlockListTooLong"; /** CannotChangeToLowerTier */ KnownStorageErrorCode["CannotChangeToLowerTier"] = "CannotChangeToLowerTier"; /** CannotVerifyCopySource */ KnownStorageErrorCode["CannotVerifyCopySource"] = "CannotVerifyCopySource"; /** ContainerAlreadyExists */ KnownStorageErrorCode["ContainerAlreadyExists"] = "ContainerAlreadyExists"; /** ContainerBeingDeleted */ KnownStorageErrorCode["ContainerBeingDeleted"] = "ContainerBeingDeleted"; /** ContainerDisabled */ KnownStorageErrorCode["ContainerDisabled"] = "ContainerDisabled"; /** ContainerNotFound */ KnownStorageErrorCode["ContainerNotFound"] = "ContainerNotFound"; /** ContentLengthLargerThanTierLimit */ KnownStorageErrorCode["ContentLengthLargerThanTierLimit"] = "ContentLengthLargerThanTierLimit"; /** CopyAcrossAccountsNotSupported */ KnownStorageErrorCode["CopyAcrossAccountsNotSupported"] = "CopyAcrossAccountsNotSupported"; /** CopyIdMismatch */ KnownStorageErrorCode["CopyIdMismatch"] = "CopyIdMismatch"; /** FeatureVersionMismatch */ KnownStorageErrorCode["FeatureVersionMismatch"] = "FeatureVersionMismatch"; /** IncrementalCopyBlobMismatch */ KnownStorageErrorCode["IncrementalCopyBlobMismatch"] = "IncrementalCopyBlobMismatch"; /** IncrementalCopyOfEarlierSnapshotNotAllowed */ KnownStorageErrorCode["IncrementalCopyOfEarlierSnapshotNotAllowed"] = "IncrementalCopyOfEarlierSnapshotNotAllowed"; /** IncrementalCopySourceMustBeSnapshot */ KnownStorageErrorCode["IncrementalCopySourceMustBeSnapshot"] = "IncrementalCopySourceMustBeSnapshot"; /** InfiniteLeaseDurationRequired */ KnownStorageErrorCode["InfiniteLeaseDurationRequired"] = "InfiniteLeaseDurationRequired"; /** InvalidBlobOrBlock */ KnownStorageErrorCode["InvalidBlobOrBlock"] = "InvalidBlobOrBlock"; /** InvalidBlobTier */ KnownStorageErrorCode["InvalidBlobTier"] = "InvalidBlobTier"; /** InvalidBlobType */ KnownStorageErrorCode["InvalidBlobType"] = "InvalidBlobType"; /** InvalidBlockId */ KnownStorageErrorCode["InvalidBlockId"] = "InvalidBlockId"; /** InvalidBlockList */ KnownStorageErrorCode["InvalidBlockList"] = "InvalidBlockList"; /** InvalidOperation */ KnownStorageErrorCode["InvalidOperation"] = "InvalidOperation"; /** InvalidPageRange */ KnownStorageErrorCode["InvalidPageRange"] = "InvalidPageRange"; /** InvalidSourceBlobType */ KnownStorageErrorCode["InvalidSourceBlobType"] = "InvalidSourceBlobType"; /** InvalidSourceBlobUrl */ KnownStorageErrorCode["InvalidSourceBlobUrl"] = "InvalidSourceBlobUrl"; /** InvalidVersionForPageBlobOperation */ KnownStorageErrorCode["InvalidVersionForPageBlobOperation"] = "InvalidVersionForPageBlobOperation"; /** LeaseAlreadyPresent */ KnownStorageErrorCode["LeaseAlreadyPresent"] = "LeaseAlreadyPresent"; /** LeaseAlreadyBroken */ KnownStorageErrorCode["LeaseAlreadyBroken"] = "LeaseAlreadyBroken"; /** LeaseIdMismatchWithBlobOperation */ KnownStorageErrorCode["LeaseIdMismatchWithBlobOperation"] = "LeaseIdMismatchWithBlobOperation"; /** LeaseIdMismatchWithContainerOperation */ KnownStorageErrorCode["LeaseIdMismatchWithContainerOperation"] = "LeaseIdMismatchWithContainerOperation"; /** LeaseIdMismatchWithLeaseOperation */ KnownStorageErrorCode["LeaseIdMismatchWithLeaseOperation"] = "LeaseIdMismatchWithLeaseOperation"; /** LeaseIdMissing */ KnownStorageErrorCode["LeaseIdMissing"] = "LeaseIdMissing"; /** LeaseIsBreakingAndCannotBeAcquired */ KnownStorageErrorCode["LeaseIsBreakingAndCannotBeAcquired"] = "LeaseIsBreakingAndCannotBeAcquired"; /** LeaseIsBreakingAndCannotBeChanged */ KnownStorageErrorCode["LeaseIsBreakingAndCannotBeChanged"] = "LeaseIsBreakingAndCannotBeChanged"; /** LeaseIsBrokenAndCannotBeRenewed */ KnownStorageErrorCode["LeaseIsBrokenAndCannotBeRenewed"] = "LeaseIsBrokenAndCannotBeRenewed"; /** LeaseLost */ KnownStorageErrorCode["LeaseLost"] = "LeaseLost"; /** LeaseNotPresentWithBlobOperation */ KnownStorageErrorCode["LeaseNotPresentWithBlobOperation"] = "LeaseNotPresentWithBlobOperation"; /** LeaseNotPresentWithContainerOperation */ KnownStorageErrorCode["LeaseNotPresentWithContainerOperation"] = "LeaseNotPresentWithContainerOperation"; /** LeaseNotPresentWithLeaseOperation */ KnownStorageErrorCode["LeaseNotPresentWithLeaseOperation"] = "LeaseNotPresentWithLeaseOperation"; /** MaxBlobSizeConditionNotMet */ KnownStorageErrorCode["MaxBlobSizeConditionNotMet"] = "MaxBlobSizeConditionNotMet"; /** NoAuthenticationInformation */ KnownStorageErrorCode["NoAuthenticationInformation"] = "NoAuthenticationInformation"; /** NoPendingCopyOperation */ KnownStorageErrorCode["NoPendingCopyOperation"] = "NoPendingCopyOperation"; /** OperationNotAllowedOnIncrementalCopyBlob */ KnownStorageErrorCode["OperationNotAllowedOnIncrementalCopyBlob"] = "OperationNotAllowedOnIncrementalCopyBlob"; /** PendingCopyOperation */ KnownStorageErrorCode["PendingCopyOperation"] = "PendingCopyOperation"; /** PreviousSnapshotCannotBeNewer */ KnownStorageErrorCode["PreviousSnapshotCannotBeNewer"] = "PreviousSnapshotCannotBeNewer"; /** PreviousSnapshotNotFound */ KnownStorageErrorCode["PreviousSnapshotNotFound"] = "PreviousSnapshotNotFound"; /** PreviousSnapshotOperationNotSupported */ KnownStorageErrorCode["PreviousSnapshotOperationNotSupported"] = "PreviousSnapshotOperationNotSupported"; /** SequenceNumberConditionNotMet */ KnownStorageErrorCode["SequenceNumberConditionNotMet"] = "SequenceNumberConditionNotMet"; /** SequenceNumberIncrementTooLarge */ KnownStorageErrorCode["SequenceNumberIncrementTooLarge"] = "SequenceNumberIncrementTooLarge"; /** SnapshotCountExceeded */ KnownStorageErrorCode["SnapshotCountExceeded"] = "SnapshotCountExceeded"; /** SnapshotOperationRateExceeded */ KnownStorageErrorCode["SnapshotOperationRateExceeded"] = "SnapshotOperationRateExceeded"; /** SnapshotsPresent */ KnownStorageErrorCode["SnapshotsPresent"] = "SnapshotsPresent"; /** SourceConditionNotMet */ KnownStorageErrorCode["SourceConditionNotMet"] = "SourceConditionNotMet"; /** SystemInUse */ KnownStorageErrorCode["SystemInUse"] = "SystemInUse"; /** TargetConditionNotMet */ KnownStorageErrorCode["TargetConditionNotMet"] = "TargetConditionNotMet"; /** UnauthorizedBlobOverwrite */ KnownStorageErrorCode["UnauthorizedBlobOverwrite"] = "UnauthorizedBlobOverwrite"; /** BlobBeingRehydrated */ KnownStorageErrorCode["BlobBeingRehydrated"] = "BlobBeingRehydrated"; /** BlobArchived */ KnownStorageErrorCode["BlobArchived"] = "BlobArchived"; /** BlobNotArchived */ KnownStorageErrorCode["BlobNotArchived"] = "BlobNotArchived"; /** AuthorizationSourceIPMismatch */ KnownStorageErrorCode["AuthorizationSourceIPMismatch"] = "AuthorizationSourceIPMismatch"; /** AuthorizationProtocolMismatch */ KnownStorageErrorCode["AuthorizationProtocolMismatch"] = "AuthorizationProtocolMismatch"; /** AuthorizationPermissionMismatch */ KnownStorageErrorCode["AuthorizationPermissionMismatch"] = "AuthorizationPermissionMismatch"; /** AuthorizationServiceMismatch */ KnownStorageErrorCode["AuthorizationServiceMismatch"] = "AuthorizationServiceMismatch"; /** AuthorizationResourceTypeMismatch */ KnownStorageErrorCode["AuthorizationResourceTypeMismatch"] = "AuthorizationResourceTypeMismatch"; /** BlobAccessTierNotSupportedForAccountType */ KnownStorageErrorCode["BlobAccessTierNotSupportedForAccountType"] = "BlobAccessTierNotSupportedForAccountType"; })(KnownStorageErrorCode || (KnownStorageErrorCode = {})); /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ const BlobServiceProperties = { serializedName: "BlobServiceProperties", xmlName: "StorageServiceProperties", type: { name: "Composite", className: "BlobServiceProperties", modelProperties: { blobAnalyticsLogging: { serializedName: "Logging", xmlName: "Logging", type: { name: "Composite", className: "Logging", }, }, hourMetrics: { serializedName: "HourMetrics", xmlName: "HourMetrics", type: { name: "Composite", className: "Metrics", }, }, minuteMetrics: { serializedName: "MinuteMetrics", xmlName: "MinuteMetrics", type: { name: "Composite", className: "Metrics", }, }, cors: { serializedName: "Cors", xmlName: "Cors", xmlIsWrapped: true, xmlElementName: "CorsRule", type: { name: "Sequence", element: { type: { name: "Composite", className: "CorsRule", }, }, }, }, defaultServiceVersion: { serializedName: "DefaultServiceVersion", xmlName: "DefaultServiceVersion", type: { name: "String", }, }, deleteRetentionPolicy: { serializedName: "DeleteRetentionPolicy", xmlName: "DeleteRetentionPolicy", type: { name: "Composite", className: "RetentionPolicy", }, }, staticWebsite: { serializedName: "StaticWebsite", xmlName: "StaticWebsite", type: { name: "Composite", className: "StaticWebsite", }, }, }, }, }; const Logging = { serializedName: "Logging", type: { name: "Composite", className: "Logging", modelProperties: { version: { serializedName: "Version", required: true, xmlName: "Version", type: { name: "String", }, }, deleteProperty: { serializedName: "Delete", required: true, xmlName: "Delete", type: { name: "Boolean", }, }, read: { serializedName: "Read", required: true, xmlName: "Read", type: { name: "Boolean", }, }, write: { serializedName: "Write", required: true, xmlName: "Write", type: { name: "Boolean", }, }, retentionPolicy: { serializedName: "RetentionPolicy", xmlName: "RetentionPolicy", type: { name: "Composite", className: "RetentionPolicy", }, }, }, }, }; const RetentionPolicy = { serializedName: "RetentionPolicy", type: { name: "Composite", className: "RetentionPolicy", modelProperties: { enabled: { serializedName: "Enabled", required: true, xmlName: "Enabled", type: { name: "Boolean", }, }, days: { constraints: { InclusiveMinimum: 1, }, serializedName: "Days", xmlName: "Days", type: { name: "Number", }, }, }, }, }; const Metrics = { serializedName: "Metrics", type: { name: "Composite", className: "Metrics", modelProperties: { version: { serializedName: "Version", xmlName: "Version", type: { name: "String", }, }, enabled: { serializedName: "Enabled", required: true, xmlName: "Enabled", type: { name: "Boolean", }, }, includeAPIs: { serializedName: "IncludeAPIs", xmlName: "IncludeAPIs", type: { name: "Boolean", }, }, retentionPolicy: { serializedName: "RetentionPolicy", xmlName: "RetentionPolicy", type: { name: "Composite", className: "RetentionPolicy", }, }, }, }, }; const CorsRule = { serializedName: "CorsRule", type: { name: "Composite", className: "CorsRule", modelProperties: { allowedOrigins: { serializedName: "AllowedOrigins", required: true, xmlName: "AllowedOrigins", type: { name: "String", }, }, allowedMethods: { serializedName: "AllowedMethods", required: true, xmlName: "AllowedMethods", type: { name: "String", }, }, allowedHeaders: { serializedName: "AllowedHeaders", required: true, xmlName: "AllowedHeaders", type: { name: "String", }, }, exposedHeaders: { serializedName: "ExposedHeaders", required: true, xmlName: "ExposedHeaders", type: { name: "String", }, }, maxAgeInSeconds: { constraints: { InclusiveMinimum: 0, }, serializedName: "MaxAgeInSeconds", required: true, xmlName: "MaxAgeInSeconds", type: { name: "Number", }, }, }, }, }; const StaticWebsite = { serializedName: "StaticWebsite", type: { name: "Composite", className: "StaticWebsite", modelProperties: { enabled: { serializedName: "Enabled", required: true, xmlName: "Enabled", type: { name: "Boolean", }, }, indexDocument: { serializedName: "IndexDocument", xmlName: "IndexDocument", type: { name: "String", }, }, errorDocument404Path: { serializedName: "ErrorDocument404Path", xmlName: "ErrorDocument404Path", type: { name: "String", }, }, defaultIndexDocumentPath: { serializedName: "DefaultIndexDocumentPath", xmlName: "DefaultIndexDocumentPath", type: { name: "String", }, }, }, }, }; const StorageError = { serializedName: "StorageError", type: { name: "Composite", className: "StorageError", modelProperties: { message: { serializedName: "Message", xmlName: "Message", type: { name: "String", }, }, copySourceStatusCode: { serializedName: "CopySourceStatusCode", xmlName: "CopySourceStatusCode", type: { name: "Number", }, }, copySourceErrorCode: { serializedName: "CopySourceErrorCode", xmlName: "CopySourceErrorCode", type: { name: "String", }, }, copySourceErrorMessage: { serializedName: "CopySourceErrorMessage", xmlName: "CopySourceErrorMessage", type: { name: "String", }, }, code: { serializedName: "Code", xmlName: "Code", type: { name: "String", }, }, authenticationErrorDetail: { serializedName: "AuthenticationErrorDetail", xmlName: "AuthenticationErrorDetail", type: { name: "String", }, }, }, }, }; const BlobServiceStatistics = { serializedName: "BlobServiceStatistics", xmlName: "StorageServiceStats", type: { name: "Composite", className: "BlobServiceStatistics", modelProperties: { geoReplication: { serializedName: "GeoReplication", xmlName: "GeoReplication", type: { name: "Composite", className: "GeoReplication", }, }, }, }, }; const GeoReplication = { serializedName: "GeoReplication", type: { name: "Composite", className: "GeoReplication", modelProperties: { status: { serializedName: "Status", required: true, xmlName: "Status", type: { name: "Enum", allowedValues: ["live", "bootstrap", "unavailable"], }, }, lastSyncOn: { serializedName: "LastSyncTime", required: true, xmlName: "LastSyncTime", type: { name: "DateTimeRfc1123", }, }, }, }, }; const ListContainersSegmentResponse = { serializedName: "ListContainersSegmentResponse", xmlName: "EnumerationResults", type: { name: "Composite", className: "ListContainersSegmentResponse", modelProperties: { serviceEndpoint: { serializedName: "ServiceEndpoint", required: true, xmlName: "ServiceEndpoint", xmlIsAttribute: true, type: { name: "String", }, }, prefix: { serializedName: "Prefix", xmlName: "Prefix", type: { name: "String", }, }, marker: { serializedName: "Marker", xmlName: "Marker", type: { name: "String", }, }, maxPageSize: { serializedName: "MaxResults", xmlName: "MaxResults", type: { name: "Number", }, }, containerItems: { serializedName: "ContainerItems", required: true, xmlName: "Containers", xmlIsWrapped: true, xmlElementName: "Container", type: { name: "Sequence", element: { type: { name: "Composite", className: "ContainerItem", }, }, }, }, continuationToken: { serializedName: "NextMarker", xmlName: "NextMarker", type: { name: "String", }, }, }, }, }; const ContainerItem = { serializedName: "ContainerItem", xmlName: "Container", type: { name: "Composite", className: "ContainerItem", modelProperties: { name: { serializedName: "Name", required: true, xmlName: "Name", type: { name: "String", }, }, deleted: { serializedName: "Deleted", xmlName: "Deleted", type: { name: "Boolean", }, }, version: { serializedName: "Version", xmlName: "Version", type: { name: "String", }, }, properties: { serializedName: "Properties", xmlName: "Properties", type: { name: "Composite", className: "ContainerProperties", }, }, metadata: { serializedName: "Metadata", xmlName: "Metadata", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, }, }, }; const ContainerProperties = { serializedName: "ContainerProperties", type: { name: "Composite", className: "ContainerProperties", modelProperties: { lastModified: { serializedName: "Last-Modified", required: true, xmlName: "Last-Modified", type: { name: "DateTimeRfc1123", }, }, etag: { serializedName: "Etag", required: true, xmlName: "Etag", type: { name: "String", }, }, leaseStatus: { serializedName: "LeaseStatus", xmlName: "LeaseStatus", type: { name: "Enum", allowedValues: ["locked", "unlocked"], }, }, leaseState: { serializedName: "LeaseState", xmlName: "LeaseState", type: { name: "Enum", allowedValues: [ "available", "leased", "expired", "breaking", "broken", ], }, }, leaseDuration: { serializedName: "LeaseDuration", xmlName: "LeaseDuration", type: { name: "Enum", allowedValues: ["infinite", "fixed"], }, }, publicAccess: { serializedName: "PublicAccess", xmlName: "PublicAccess", type: { name: "Enum", allowedValues: ["container", "blob"], }, }, hasImmutabilityPolicy: { serializedName: "HasImmutabilityPolicy", xmlName: "HasImmutabilityPolicy", type: { name: "Boolean", }, }, hasLegalHold: { serializedName: "HasLegalHold", xmlName: "HasLegalHold", type: { name: "Boolean", }, }, defaultEncryptionScope: { serializedName: "DefaultEncryptionScope", xmlName: "DefaultEncryptionScope", type: { name: "String", }, }, preventEncryptionScopeOverride: { serializedName: "DenyEncryptionScopeOverride", xmlName: "DenyEncryptionScopeOverride", type: { name: "Boolean", }, }, deletedOn: { serializedName: "DeletedTime", xmlName: "DeletedTime", type: { name: "DateTimeRfc1123", }, }, remainingRetentionDays: { serializedName: "RemainingRetentionDays", xmlName: "RemainingRetentionDays", type: { name: "Number", }, }, isImmutableStorageWithVersioningEnabled: { serializedName: "ImmutableStorageWithVersioningEnabled", xmlName: "ImmutableStorageWithVersioningEnabled", type: { name: "Boolean", }, }, }, }, }; const KeyInfo = { serializedName: "KeyInfo", type: { name: "Composite", className: "KeyInfo", modelProperties: { startsOn: { serializedName: "Start", required: true, xmlName: "Start", type: { name: "String", }, }, expiresOn: { serializedName: "Expiry", required: true, xmlName: "Expiry", type: { name: "String", }, }, delegatedUserTid: { serializedName: "DelegatedUserTid", xmlName: "DelegatedUserTid", type: { name: "String", }, }, }, }, }; const UserDelegationKey = { serializedName: "UserDelegationKey", type: { name: "Composite", className: "UserDelegationKey", modelProperties: { signedObjectId: { serializedName: "SignedOid", required: true, xmlName: "SignedOid", type: { name: "String", }, }, signedTenantId: { serializedName: "SignedTid", required: true, xmlName: "SignedTid", type: { name: "String", }, }, signedStartsOn: { serializedName: "SignedStart", required: true, xmlName: "SignedStart", type: { name: "String", }, }, signedExpiresOn: { serializedName: "SignedExpiry", required: true, xmlName: "SignedExpiry", type: { name: "String", }, }, signedService: { serializedName: "SignedService", required: true, xmlName: "SignedService", type: { name: "String", }, }, signedVersion: { serializedName: "SignedVersion", required: true, xmlName: "SignedVersion", type: { name: "String", }, }, signedDelegatedUserTenantId: { serializedName: "SignedDelegatedUserTid", xmlName: "SignedDelegatedUserTid", type: { name: "String", }, }, value: { serializedName: "Value", required: true, xmlName: "Value", type: { name: "String", }, }, }, }, }; const FilterBlobSegment = { serializedName: "FilterBlobSegment", xmlName: "EnumerationResults", type: { name: "Composite", className: "FilterBlobSegment", modelProperties: { serviceEndpoint: { serializedName: "ServiceEndpoint", required: true, xmlName: "ServiceEndpoint", xmlIsAttribute: true, type: { name: "String", }, }, where: { serializedName: "Where", required: true, xmlName: "Where", type: { name: "String", }, }, blobs: { serializedName: "Blobs", required: true, xmlName: "Blobs", xmlIsWrapped: true, xmlElementName: "Blob", type: { name: "Sequence", element: { type: { name: "Composite", className: "FilterBlobItem", }, }, }, }, continuationToken: { serializedName: "NextMarker", xmlName: "NextMarker", type: { name: "String", }, }, }, }, }; const FilterBlobItem = { serializedName: "FilterBlobItem", xmlName: "Blob", type: { name: "Composite", className: "FilterBlobItem", modelProperties: { name: { serializedName: "Name", required: true, xmlName: "Name", type: { name: "String", }, }, containerName: { serializedName: "ContainerName", required: true, xmlName: "ContainerName", type: { name: "String", }, }, tags: { serializedName: "Tags", xmlName: "Tags", type: { name: "Composite", className: "BlobTags", }, }, }, }, }; const BlobTags = { serializedName: "BlobTags", xmlName: "Tags", type: { name: "Composite", className: "BlobTags", modelProperties: { blobTagSet: { serializedName: "BlobTagSet", required: true, xmlName: "TagSet", xmlIsWrapped: true, xmlElementName: "Tag", type: { name: "Sequence", element: { type: { name: "Composite", className: "BlobTag", }, }, }, }, }, }, }; const BlobTag = { serializedName: "BlobTag", xmlName: "Tag", type: { name: "Composite", className: "BlobTag", modelProperties: { key: { serializedName: "Key", required: true, xmlName: "Key", type: { name: "String", }, }, value: { serializedName: "Value", required: true, xmlName: "Value", type: { name: "String", }, }, }, }, }; const SignedIdentifier = { serializedName: "SignedIdentifier", xmlName: "SignedIdentifier", type: { name: "Composite", className: "SignedIdentifier", modelProperties: { id: { serializedName: "Id", required: true, xmlName: "Id", type: { name: "String", }, }, accessPolicy: { serializedName: "AccessPolicy", xmlName: "AccessPolicy", type: { name: "Composite", className: "AccessPolicy", }, }, }, }, }; const AccessPolicy = { serializedName: "AccessPolicy", type: { name: "Composite", className: "AccessPolicy", modelProperties: { startsOn: { serializedName: "Start", xmlName: "Start", type: { name: "String", }, }, expiresOn: { serializedName: "Expiry", xmlName: "Expiry", type: { name: "String", }, }, permissions: { serializedName: "Permission", xmlName: "Permission", type: { name: "String", }, }, }, }, }; const ListBlobsFlatSegmentResponse = { serializedName: "ListBlobsFlatSegmentResponse", xmlName: "EnumerationResults", type: { name: "Composite", className: "ListBlobsFlatSegmentResponse", modelProperties: { serviceEndpoint: { serializedName: "ServiceEndpoint", required: true, xmlName: "ServiceEndpoint", xmlIsAttribute: true, type: { name: "String", }, }, containerName: { serializedName: "ContainerName", required: true, xmlName: "ContainerName", xmlIsAttribute: true, type: { name: "String", }, }, prefix: { serializedName: "Prefix", xmlName: "Prefix", type: { name: "String", }, }, marker: { serializedName: "Marker", xmlName: "Marker", type: { name: "String", }, }, maxPageSize: { serializedName: "MaxResults", xmlName: "MaxResults", type: { name: "Number", }, }, segment: { serializedName: "Segment", xmlName: "Blobs", type: { name: "Composite", className: "BlobFlatListSegment", }, }, continuationToken: { serializedName: "NextMarker", xmlName: "NextMarker", type: { name: "String", }, }, }, }, }; const BlobFlatListSegment = { serializedName: "BlobFlatListSegment", xmlName: "Blobs", type: { name: "Composite", className: "BlobFlatListSegment", modelProperties: { blobItems: { serializedName: "BlobItems", required: true, xmlName: "BlobItems", xmlElementName: "Blob", type: { name: "Sequence", element: { type: { name: "Composite", className: "BlobItemInternal", }, }, }, }, }, }, }; const BlobItemInternal = { serializedName: "BlobItemInternal", xmlName: "Blob", type: { name: "Composite", className: "BlobItemInternal", modelProperties: { name: { serializedName: "Name", xmlName: "Name", type: { name: "Composite", className: "BlobName", }, }, deleted: { serializedName: "Deleted", required: true, xmlName: "Deleted", type: { name: "Boolean", }, }, snapshot: { serializedName: "Snapshot", required: true, xmlName: "Snapshot", type: { name: "String", }, }, versionId: { serializedName: "VersionId", xmlName: "VersionId", type: { name: "String", }, }, isCurrentVersion: { serializedName: "IsCurrentVersion", xmlName: "IsCurrentVersion", type: { name: "Boolean", }, }, properties: { serializedName: "Properties", xmlName: "Properties", type: { name: "Composite", className: "BlobPropertiesInternal", }, }, metadata: { serializedName: "Metadata", xmlName: "Metadata", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, blobTags: { serializedName: "BlobTags", xmlName: "Tags", type: { name: "Composite", className: "BlobTags", }, }, objectReplicationMetadata: { serializedName: "ObjectReplicationMetadata", xmlName: "OrMetadata", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, hasVersionsOnly: { serializedName: "HasVersionsOnly", xmlName: "HasVersionsOnly", type: { name: "Boolean", }, }, }, }, }; const BlobName = { serializedName: "BlobName", type: { name: "Composite", className: "BlobName", modelProperties: { encoded: { serializedName: "Encoded", xmlName: "Encoded", xmlIsAttribute: true, type: { name: "Boolean", }, }, content: { serializedName: "content", xmlName: "content", xmlIsMsText: true, type: { name: "String", }, }, }, }, }; const BlobPropertiesInternal = { serializedName: "BlobPropertiesInternal", xmlName: "Properties", type: { name: "Composite", className: "BlobPropertiesInternal", modelProperties: { createdOn: { serializedName: "Creation-Time", xmlName: "Creation-Time", type: { name: "DateTimeRfc1123", }, }, lastModified: { serializedName: "Last-Modified", required: true, xmlName: "Last-Modified", type: { name: "DateTimeRfc1123", }, }, etag: { serializedName: "Etag", required: true, xmlName: "Etag", type: { name: "String", }, }, contentLength: { serializedName: "Content-Length", xmlName: "Content-Length", type: { name: "Number", }, }, contentType: { serializedName: "Content-Type", xmlName: "Content-Type", type: { name: "String", }, }, contentEncoding: { serializedName: "Content-Encoding", xmlName: "Content-Encoding", type: { name: "String", }, }, contentLanguage: { serializedName: "Content-Language", xmlName: "Content-Language", type: { name: "String", }, }, contentMD5: { serializedName: "Content-MD5", xmlName: "Content-MD5", type: { name: "ByteArray", }, }, contentDisposition: { serializedName: "Content-Disposition", xmlName: "Content-Disposition", type: { name: "String", }, }, cacheControl: { serializedName: "Cache-Control", xmlName: "Cache-Control", type: { name: "String", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, blobType: { serializedName: "BlobType", xmlName: "BlobType", type: { name: "Enum", allowedValues: ["BlockBlob", "PageBlob", "AppendBlob"], }, }, leaseStatus: { serializedName: "LeaseStatus", xmlName: "LeaseStatus", type: { name: "Enum", allowedValues: ["locked", "unlocked"], }, }, leaseState: { serializedName: "LeaseState", xmlName: "LeaseState", type: { name: "Enum", allowedValues: [ "available", "leased", "expired", "breaking", "broken", ], }, }, leaseDuration: { serializedName: "LeaseDuration", xmlName: "LeaseDuration", type: { name: "Enum", allowedValues: ["infinite", "fixed"], }, }, copyId: { serializedName: "CopyId", xmlName: "CopyId", type: { name: "String", }, }, copyStatus: { serializedName: "CopyStatus", xmlName: "CopyStatus", type: { name: "Enum", allowedValues: ["pending", "success", "aborted", "failed"], }, }, copySource: { serializedName: "CopySource", xmlName: "CopySource", type: { name: "String", }, }, copyProgress: { serializedName: "CopyProgress", xmlName: "CopyProgress", type: { name: "String", }, }, copyCompletedOn: { serializedName: "CopyCompletionTime", xmlName: "CopyCompletionTime", type: { name: "DateTimeRfc1123", }, }, copyStatusDescription: { serializedName: "CopyStatusDescription", xmlName: "CopyStatusDescription", type: { name: "String", }, }, serverEncrypted: { serializedName: "ServerEncrypted", xmlName: "ServerEncrypted", type: { name: "Boolean", }, }, incrementalCopy: { serializedName: "IncrementalCopy", xmlName: "IncrementalCopy", type: { name: "Boolean", }, }, destinationSnapshot: { serializedName: "DestinationSnapshot", xmlName: "DestinationSnapshot", type: { name: "String", }, }, deletedOn: { serializedName: "DeletedTime", xmlName: "DeletedTime", type: { name: "DateTimeRfc1123", }, }, remainingRetentionDays: { serializedName: "RemainingRetentionDays", xmlName: "RemainingRetentionDays", type: { name: "Number", }, }, accessTier: { serializedName: "AccessTier", xmlName: "AccessTier", type: { name: "Enum", allowedValues: [ "P4", "P6", "P10", "P15", "P20", "P30", "P40", "P50", "P60", "P70", "P80", "Hot", "Cool", "Archive", "Cold", ], }, }, accessTierInferred: { serializedName: "AccessTierInferred", xmlName: "AccessTierInferred", type: { name: "Boolean", }, }, archiveStatus: { serializedName: "ArchiveStatus", xmlName: "ArchiveStatus", type: { name: "Enum", allowedValues: [ "rehydrate-pending-to-hot", "rehydrate-pending-to-cool", "rehydrate-pending-to-cold", ], }, }, customerProvidedKeySha256: { serializedName: "CustomerProvidedKeySha256", xmlName: "CustomerProvidedKeySha256", type: { name: "String", }, }, encryptionScope: { serializedName: "EncryptionScope", xmlName: "EncryptionScope", type: { name: "String", }, }, accessTierChangedOn: { serializedName: "AccessTierChangeTime", xmlName: "AccessTierChangeTime", type: { name: "DateTimeRfc1123", }, }, tagCount: { serializedName: "TagCount", xmlName: "TagCount", type: { name: "Number", }, }, expiresOn: { serializedName: "Expiry-Time", xmlName: "Expiry-Time", type: { name: "DateTimeRfc1123", }, }, isSealed: { serializedName: "Sealed", xmlName: "Sealed", type: { name: "Boolean", }, }, rehydratePriority: { serializedName: "RehydratePriority", xmlName: "RehydratePriority", type: { name: "Enum", allowedValues: ["High", "Standard"], }, }, lastAccessedOn: { serializedName: "LastAccessTime", xmlName: "LastAccessTime", type: { name: "DateTimeRfc1123", }, }, immutabilityPolicyExpiresOn: { serializedName: "ImmutabilityPolicyUntilDate", xmlName: "ImmutabilityPolicyUntilDate", type: { name: "DateTimeRfc1123", }, }, immutabilityPolicyMode: { serializedName: "ImmutabilityPolicyMode", xmlName: "ImmutabilityPolicyMode", type: { name: "Enum", allowedValues: ["Mutable", "Unlocked", "Locked"], }, }, legalHold: { serializedName: "LegalHold", xmlName: "LegalHold", type: { name: "Boolean", }, }, }, }, }; const ListBlobsHierarchySegmentResponse = { serializedName: "ListBlobsHierarchySegmentResponse", xmlName: "EnumerationResults", type: { name: "Composite", className: "ListBlobsHierarchySegmentResponse", modelProperties: { serviceEndpoint: { serializedName: "ServiceEndpoint", required: true, xmlName: "ServiceEndpoint", xmlIsAttribute: true, type: { name: "String", }, }, containerName: { serializedName: "ContainerName", required: true, xmlName: "ContainerName", xmlIsAttribute: true, type: { name: "String", }, }, prefix: { serializedName: "Prefix", xmlName: "Prefix", type: { name: "String", }, }, marker: { serializedName: "Marker", xmlName: "Marker", type: { name: "String", }, }, maxPageSize: { serializedName: "MaxResults", xmlName: "MaxResults", type: { name: "Number", }, }, delimiter: { serializedName: "Delimiter", xmlName: "Delimiter", type: { name: "String", }, }, segment: { serializedName: "Segment", xmlName: "Blobs", type: { name: "Composite", className: "BlobHierarchyListSegment", }, }, continuationToken: { serializedName: "NextMarker", xmlName: "NextMarker", type: { name: "String", }, }, }, }, }; const BlobHierarchyListSegment = { serializedName: "BlobHierarchyListSegment", xmlName: "Blobs", type: { name: "Composite", className: "BlobHierarchyListSegment", modelProperties: { blobPrefixes: { serializedName: "BlobPrefixes", xmlName: "BlobPrefixes", xmlElementName: "BlobPrefix", type: { name: "Sequence", element: { type: { name: "Composite", className: "BlobPrefix", }, }, }, }, blobItems: { serializedName: "BlobItems", required: true, xmlName: "BlobItems", xmlElementName: "Blob", type: { name: "Sequence", element: { type: { name: "Composite", className: "BlobItemInternal", }, }, }, }, }, }, }; const BlobPrefix = { serializedName: "BlobPrefix", type: { name: "Composite", className: "BlobPrefix", modelProperties: { name: { serializedName: "Name", xmlName: "Name", type: { name: "Composite", className: "BlobName", }, }, }, }, }; const BlockLookupList = { serializedName: "BlockLookupList", xmlName: "BlockList", type: { name: "Composite", className: "BlockLookupList", modelProperties: { committed: { serializedName: "Committed", xmlName: "Committed", xmlElementName: "Committed", type: { name: "Sequence", element: { type: { name: "String", }, }, }, }, uncommitted: { serializedName: "Uncommitted", xmlName: "Uncommitted", xmlElementName: "Uncommitted", type: { name: "Sequence", element: { type: { name: "String", }, }, }, }, latest: { serializedName: "Latest", xmlName: "Latest", xmlElementName: "Latest", type: { name: "Sequence", element: { type: { name: "String", }, }, }, }, }, }, }; const BlockList = { serializedName: "BlockList", type: { name: "Composite", className: "BlockList", modelProperties: { committedBlocks: { serializedName: "CommittedBlocks", xmlName: "CommittedBlocks", xmlIsWrapped: true, xmlElementName: "Block", type: { name: "Sequence", element: { type: { name: "Composite", className: "Block", }, }, }, }, uncommittedBlocks: { serializedName: "UncommittedBlocks", xmlName: "UncommittedBlocks", xmlIsWrapped: true, xmlElementName: "Block", type: { name: "Sequence", element: { type: { name: "Composite", className: "Block", }, }, }, }, }, }, }; const Block = { serializedName: "Block", type: { name: "Composite", className: "Block", modelProperties: { name: { serializedName: "Name", required: true, xmlName: "Name", type: { name: "String", }, }, size: { serializedName: "Size", required: true, xmlName: "Size", type: { name: "Number", }, }, }, }, }; const PageList = { serializedName: "PageList", type: { name: "Composite", className: "PageList", modelProperties: { pageRange: { serializedName: "PageRange", xmlName: "PageRange", xmlElementName: "PageRange", type: { name: "Sequence", element: { type: { name: "Composite", className: "PageRange", }, }, }, }, clearRange: { serializedName: "ClearRange", xmlName: "ClearRange", xmlElementName: "ClearRange", type: { name: "Sequence", element: { type: { name: "Composite", className: "ClearRange", }, }, }, }, continuationToken: { serializedName: "NextMarker", xmlName: "NextMarker", type: { name: "String", }, }, }, }, }; const PageRange = { serializedName: "PageRange", xmlName: "PageRange", type: { name: "Composite", className: "PageRange", modelProperties: { start: { serializedName: "Start", required: true, xmlName: "Start", type: { name: "Number", }, }, end: { serializedName: "End", required: true, xmlName: "End", type: { name: "Number", }, }, }, }, }; const ClearRange = { serializedName: "ClearRange", xmlName: "ClearRange", type: { name: "Composite", className: "ClearRange", modelProperties: { start: { serializedName: "Start", required: true, xmlName: "Start", type: { name: "Number", }, }, end: { serializedName: "End", required: true, xmlName: "End", type: { name: "Number", }, }, }, }, }; const QueryRequest = { serializedName: "QueryRequest", xmlName: "QueryRequest", type: { name: "Composite", className: "QueryRequest", modelProperties: { queryType: { serializedName: "QueryType", required: true, xmlName: "QueryType", type: { name: "String", }, }, expression: { serializedName: "Expression", required: true, xmlName: "Expression", type: { name: "String", }, }, inputSerialization: { serializedName: "InputSerialization", xmlName: "InputSerialization", type: { name: "Composite", className: "QuerySerialization", }, }, outputSerialization: { serializedName: "OutputSerialization", xmlName: "OutputSerialization", type: { name: "Composite", className: "QuerySerialization", }, }, }, }, }; const QuerySerialization = { serializedName: "QuerySerialization", type: { name: "Composite", className: "QuerySerialization", modelProperties: { format: { serializedName: "Format", xmlName: "Format", type: { name: "Composite", className: "QueryFormat", }, }, }, }, }; const QueryFormat = { serializedName: "QueryFormat", type: { name: "Composite", className: "QueryFormat", modelProperties: { type: { serializedName: "Type", required: true, xmlName: "Type", type: { name: "Enum", allowedValues: ["delimited", "json", "arrow", "parquet"], }, }, delimitedTextConfiguration: { serializedName: "DelimitedTextConfiguration", xmlName: "DelimitedTextConfiguration", type: { name: "Composite", className: "DelimitedTextConfiguration", }, }, jsonTextConfiguration: { serializedName: "JsonTextConfiguration", xmlName: "JsonTextConfiguration", type: { name: "Composite", className: "JsonTextConfiguration", }, }, arrowConfiguration: { serializedName: "ArrowConfiguration", xmlName: "ArrowConfiguration", type: { name: "Composite", className: "ArrowConfiguration", }, }, parquetTextConfiguration: { serializedName: "ParquetTextConfiguration", xmlName: "ParquetTextConfiguration", type: { name: "Dictionary", value: { type: { name: "any" } }, }, }, }, }, }; const DelimitedTextConfiguration = { serializedName: "DelimitedTextConfiguration", xmlName: "DelimitedTextConfiguration", type: { name: "Composite", className: "DelimitedTextConfiguration", modelProperties: { columnSeparator: { serializedName: "ColumnSeparator", xmlName: "ColumnSeparator", type: { name: "String", }, }, fieldQuote: { serializedName: "FieldQuote", xmlName: "FieldQuote", type: { name: "String", }, }, recordSeparator: { serializedName: "RecordSeparator", xmlName: "RecordSeparator", type: { name: "String", }, }, escapeChar: { serializedName: "EscapeChar", xmlName: "EscapeChar", type: { name: "String", }, }, headersPresent: { serializedName: "HeadersPresent", xmlName: "HasHeaders", type: { name: "Boolean", }, }, }, }, }; const JsonTextConfiguration = { serializedName: "JsonTextConfiguration", xmlName: "JsonTextConfiguration", type: { name: "Composite", className: "JsonTextConfiguration", modelProperties: { recordSeparator: { serializedName: "RecordSeparator", xmlName: "RecordSeparator", type: { name: "String", }, }, }, }, }; const ArrowConfiguration = { serializedName: "ArrowConfiguration", xmlName: "ArrowConfiguration", type: { name: "Composite", className: "ArrowConfiguration", modelProperties: { schema: { serializedName: "Schema", required: true, xmlName: "Schema", xmlIsWrapped: true, xmlElementName: "Field", type: { name: "Sequence", element: { type: { name: "Composite", className: "ArrowField", }, }, }, }, }, }, }; const ArrowField = { serializedName: "ArrowField", xmlName: "Field", type: { name: "Composite", className: "ArrowField", modelProperties: { type: { serializedName: "Type", required: true, xmlName: "Type", type: { name: "String", }, }, name: { serializedName: "Name", xmlName: "Name", type: { name: "String", }, }, precision: { serializedName: "Precision", xmlName: "Precision", type: { name: "Number", }, }, scale: { serializedName: "Scale", xmlName: "Scale", type: { name: "Number", }, }, }, }, }; const ServiceSetPropertiesHeaders = { serializedName: "Service_setPropertiesHeaders", type: { name: "Composite", className: "ServiceSetPropertiesHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceSetPropertiesExceptionHeaders = { serializedName: "Service_setPropertiesExceptionHeaders", type: { name: "Composite", className: "ServiceSetPropertiesExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceGetPropertiesHeaders = { serializedName: "Service_getPropertiesHeaders", type: { name: "Composite", className: "ServiceGetPropertiesHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceGetPropertiesExceptionHeaders = { serializedName: "Service_getPropertiesExceptionHeaders", type: { name: "Composite", className: "ServiceGetPropertiesExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceGetStatisticsHeaders = { serializedName: "Service_getStatisticsHeaders", type: { name: "Composite", className: "ServiceGetStatisticsHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceGetStatisticsExceptionHeaders = { serializedName: "Service_getStatisticsExceptionHeaders", type: { name: "Composite", className: "ServiceGetStatisticsExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceListContainersSegmentHeaders = { serializedName: "Service_listContainersSegmentHeaders", type: { name: "Composite", className: "ServiceListContainersSegmentHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceListContainersSegmentExceptionHeaders = { serializedName: "Service_listContainersSegmentExceptionHeaders", type: { name: "Composite", className: "ServiceListContainersSegmentExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceGetUserDelegationKeyHeaders = { serializedName: "Service_getUserDelegationKeyHeaders", type: { name: "Composite", className: "ServiceGetUserDelegationKeyHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceGetUserDelegationKeyExceptionHeaders = { serializedName: "Service_getUserDelegationKeyExceptionHeaders", type: { name: "Composite", className: "ServiceGetUserDelegationKeyExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceGetAccountInfoHeaders = { serializedName: "Service_getAccountInfoHeaders", type: { name: "Composite", className: "ServiceGetAccountInfoHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, skuName: { serializedName: "x-ms-sku-name", xmlName: "x-ms-sku-name", type: { name: "Enum", allowedValues: [ "Standard_LRS", "Standard_GRS", "Standard_RAGRS", "Standard_ZRS", "Premium_LRS", "Standard_GZRS", "Premium_ZRS", "Standard_RAGZRS", ], }, }, accountKind: { serializedName: "x-ms-account-kind", xmlName: "x-ms-account-kind", type: { name: "Enum", allowedValues: [ "Storage", "BlobStorage", "StorageV2", "FileStorage", "BlockBlobStorage", ], }, }, isHierarchicalNamespaceEnabled: { serializedName: "x-ms-is-hns-enabled", xmlName: "x-ms-is-hns-enabled", type: { name: "Boolean", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceGetAccountInfoExceptionHeaders = { serializedName: "Service_getAccountInfoExceptionHeaders", type: { name: "Composite", className: "ServiceGetAccountInfoExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceSubmitBatchHeaders = { serializedName: "Service_submitBatchHeaders", type: { name: "Composite", className: "ServiceSubmitBatchHeaders", modelProperties: { contentType: { serializedName: "content-type", xmlName: "content-type", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceSubmitBatchExceptionHeaders = { serializedName: "Service_submitBatchExceptionHeaders", type: { name: "Composite", className: "ServiceSubmitBatchExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceFilterBlobsHeaders = { serializedName: "Service_filterBlobsHeaders", type: { name: "Composite", className: "ServiceFilterBlobsHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ServiceFilterBlobsExceptionHeaders = { serializedName: "Service_filterBlobsExceptionHeaders", type: { name: "Composite", className: "ServiceFilterBlobsExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerCreateHeaders = { serializedName: "Container_createHeaders", type: { name: "Composite", className: "ContainerCreateHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerCreateExceptionHeaders = { serializedName: "Container_createExceptionHeaders", type: { name: "Composite", className: "ContainerCreateExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerGetPropertiesHeaders = { serializedName: "Container_getPropertiesHeaders", type: { name: "Composite", className: "ContainerGetPropertiesHeaders", modelProperties: { metadata: { serializedName: "x-ms-meta", headerCollectionPrefix: "x-ms-meta-", xmlName: "x-ms-meta", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, leaseDuration: { serializedName: "x-ms-lease-duration", xmlName: "x-ms-lease-duration", type: { name: "Enum", allowedValues: ["infinite", "fixed"], }, }, leaseState: { serializedName: "x-ms-lease-state", xmlName: "x-ms-lease-state", type: { name: "Enum", allowedValues: [ "available", "leased", "expired", "breaking", "broken", ], }, }, leaseStatus: { serializedName: "x-ms-lease-status", xmlName: "x-ms-lease-status", type: { name: "Enum", allowedValues: ["locked", "unlocked"], }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, blobPublicAccess: { serializedName: "x-ms-blob-public-access", xmlName: "x-ms-blob-public-access", type: { name: "Enum", allowedValues: ["container", "blob"], }, }, hasImmutabilityPolicy: { serializedName: "x-ms-has-immutability-policy", xmlName: "x-ms-has-immutability-policy", type: { name: "Boolean", }, }, hasLegalHold: { serializedName: "x-ms-has-legal-hold", xmlName: "x-ms-has-legal-hold", type: { name: "Boolean", }, }, defaultEncryptionScope: { serializedName: "x-ms-default-encryption-scope", xmlName: "x-ms-default-encryption-scope", type: { name: "String", }, }, denyEncryptionScopeOverride: { serializedName: "x-ms-deny-encryption-scope-override", xmlName: "x-ms-deny-encryption-scope-override", type: { name: "Boolean", }, }, isImmutableStorageWithVersioningEnabled: { serializedName: "x-ms-immutable-storage-with-versioning-enabled", xmlName: "x-ms-immutable-storage-with-versioning-enabled", type: { name: "Boolean", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerGetPropertiesExceptionHeaders = { serializedName: "Container_getPropertiesExceptionHeaders", type: { name: "Composite", className: "ContainerGetPropertiesExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerDeleteHeaders = { serializedName: "Container_deleteHeaders", type: { name: "Composite", className: "ContainerDeleteHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerDeleteExceptionHeaders = { serializedName: "Container_deleteExceptionHeaders", type: { name: "Composite", className: "ContainerDeleteExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerSetMetadataHeaders = { serializedName: "Container_setMetadataHeaders", type: { name: "Composite", className: "ContainerSetMetadataHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerSetMetadataExceptionHeaders = { serializedName: "Container_setMetadataExceptionHeaders", type: { name: "Composite", className: "ContainerSetMetadataExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerGetAccessPolicyHeaders = { serializedName: "Container_getAccessPolicyHeaders", type: { name: "Composite", className: "ContainerGetAccessPolicyHeaders", modelProperties: { blobPublicAccess: { serializedName: "x-ms-blob-public-access", xmlName: "x-ms-blob-public-access", type: { name: "Enum", allowedValues: ["container", "blob"], }, }, etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerGetAccessPolicyExceptionHeaders = { serializedName: "Container_getAccessPolicyExceptionHeaders", type: { name: "Composite", className: "ContainerGetAccessPolicyExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerSetAccessPolicyHeaders = { serializedName: "Container_setAccessPolicyHeaders", type: { name: "Composite", className: "ContainerSetAccessPolicyHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerSetAccessPolicyExceptionHeaders = { serializedName: "Container_setAccessPolicyExceptionHeaders", type: { name: "Composite", className: "ContainerSetAccessPolicyExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerRestoreHeaders = { serializedName: "Container_restoreHeaders", type: { name: "Composite", className: "ContainerRestoreHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerRestoreExceptionHeaders = { serializedName: "Container_restoreExceptionHeaders", type: { name: "Composite", className: "ContainerRestoreExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerRenameHeaders = { serializedName: "Container_renameHeaders", type: { name: "Composite", className: "ContainerRenameHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerRenameExceptionHeaders = { serializedName: "Container_renameExceptionHeaders", type: { name: "Composite", className: "ContainerRenameExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerSubmitBatchHeaders = { serializedName: "Container_submitBatchHeaders", type: { name: "Composite", className: "ContainerSubmitBatchHeaders", modelProperties: { contentType: { serializedName: "content-type", xmlName: "content-type", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, }, }, }; const ContainerSubmitBatchExceptionHeaders = { serializedName: "Container_submitBatchExceptionHeaders", type: { name: "Composite", className: "ContainerSubmitBatchExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerFilterBlobsHeaders = { serializedName: "Container_filterBlobsHeaders", type: { name: "Composite", className: "ContainerFilterBlobsHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const ContainerFilterBlobsExceptionHeaders = { serializedName: "Container_filterBlobsExceptionHeaders", type: { name: "Composite", className: "ContainerFilterBlobsExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerAcquireLeaseHeaders = { serializedName: "Container_acquireLeaseHeaders", type: { name: "Composite", className: "ContainerAcquireLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, leaseId: { serializedName: "x-ms-lease-id", xmlName: "x-ms-lease-id", type: { name: "String", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const ContainerAcquireLeaseExceptionHeaders = { serializedName: "Container_acquireLeaseExceptionHeaders", type: { name: "Composite", className: "ContainerAcquireLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerReleaseLeaseHeaders = { serializedName: "Container_releaseLeaseHeaders", type: { name: "Composite", className: "ContainerReleaseLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const ContainerReleaseLeaseExceptionHeaders = { serializedName: "Container_releaseLeaseExceptionHeaders", type: { name: "Composite", className: "ContainerReleaseLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerRenewLeaseHeaders = { serializedName: "Container_renewLeaseHeaders", type: { name: "Composite", className: "ContainerRenewLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, leaseId: { serializedName: "x-ms-lease-id", xmlName: "x-ms-lease-id", type: { name: "String", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const ContainerRenewLeaseExceptionHeaders = { serializedName: "Container_renewLeaseExceptionHeaders", type: { name: "Composite", className: "ContainerRenewLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerBreakLeaseHeaders = { serializedName: "Container_breakLeaseHeaders", type: { name: "Composite", className: "ContainerBreakLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, leaseTime: { serializedName: "x-ms-lease-time", xmlName: "x-ms-lease-time", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const ContainerBreakLeaseExceptionHeaders = { serializedName: "Container_breakLeaseExceptionHeaders", type: { name: "Composite", className: "ContainerBreakLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerChangeLeaseHeaders = { serializedName: "Container_changeLeaseHeaders", type: { name: "Composite", className: "ContainerChangeLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, leaseId: { serializedName: "x-ms-lease-id", xmlName: "x-ms-lease-id", type: { name: "String", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const ContainerChangeLeaseExceptionHeaders = { serializedName: "Container_changeLeaseExceptionHeaders", type: { name: "Composite", className: "ContainerChangeLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerListBlobFlatSegmentHeaders = { serializedName: "Container_listBlobFlatSegmentHeaders", type: { name: "Composite", className: "ContainerListBlobFlatSegmentHeaders", modelProperties: { contentType: { serializedName: "content-type", xmlName: "content-type", type: { name: "String", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerListBlobFlatSegmentExceptionHeaders = { serializedName: "Container_listBlobFlatSegmentExceptionHeaders", type: { name: "Composite", className: "ContainerListBlobFlatSegmentExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerListBlobHierarchySegmentHeaders = { serializedName: "Container_listBlobHierarchySegmentHeaders", type: { name: "Composite", className: "ContainerListBlobHierarchySegmentHeaders", modelProperties: { contentType: { serializedName: "content-type", xmlName: "content-type", type: { name: "String", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerListBlobHierarchySegmentExceptionHeaders = { serializedName: "Container_listBlobHierarchySegmentExceptionHeaders", type: { name: "Composite", className: "ContainerListBlobHierarchySegmentExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const ContainerGetAccountInfoHeaders = { serializedName: "Container_getAccountInfoHeaders", type: { name: "Composite", className: "ContainerGetAccountInfoHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, skuName: { serializedName: "x-ms-sku-name", xmlName: "x-ms-sku-name", type: { name: "Enum", allowedValues: [ "Standard_LRS", "Standard_GRS", "Standard_RAGRS", "Standard_ZRS", "Premium_LRS", "Standard_GZRS", "Premium_ZRS", "Standard_RAGZRS", ], }, }, accountKind: { serializedName: "x-ms-account-kind", xmlName: "x-ms-account-kind", type: { name: "Enum", allowedValues: [ "Storage", "BlobStorage", "StorageV2", "FileStorage", "BlockBlobStorage", ], }, }, isHierarchicalNamespaceEnabled: { serializedName: "x-ms-is-hns-enabled", xmlName: "x-ms-is-hns-enabled", type: { name: "Boolean", }, }, }, }, }; const ContainerGetAccountInfoExceptionHeaders = { serializedName: "Container_getAccountInfoExceptionHeaders", type: { name: "Composite", className: "ContainerGetAccountInfoExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobDownloadHeaders = { serializedName: "Blob_downloadHeaders", type: { name: "Composite", className: "BlobDownloadHeaders", modelProperties: { lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, createdOn: { serializedName: "x-ms-creation-time", xmlName: "x-ms-creation-time", type: { name: "DateTimeRfc1123", }, }, metadata: { serializedName: "x-ms-meta", headerCollectionPrefix: "x-ms-meta-", xmlName: "x-ms-meta", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, objectReplicationPolicyId: { serializedName: "x-ms-or-policy-id", xmlName: "x-ms-or-policy-id", type: { name: "String", }, }, objectReplicationRules: { serializedName: "x-ms-or", headerCollectionPrefix: "x-ms-or-", xmlName: "x-ms-or", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, contentLength: { serializedName: "content-length", xmlName: "content-length", type: { name: "Number", }, }, contentType: { serializedName: "content-type", xmlName: "content-type", type: { name: "String", }, }, contentRange: { serializedName: "content-range", xmlName: "content-range", type: { name: "String", }, }, etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, contentEncoding: { serializedName: "content-encoding", xmlName: "content-encoding", type: { name: "String", }, }, cacheControl: { serializedName: "cache-control", xmlName: "cache-control", type: { name: "String", }, }, contentDisposition: { serializedName: "content-disposition", xmlName: "content-disposition", type: { name: "String", }, }, contentLanguage: { serializedName: "content-language", xmlName: "content-language", type: { name: "String", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, blobType: { serializedName: "x-ms-blob-type", xmlName: "x-ms-blob-type", type: { name: "Enum", allowedValues: ["BlockBlob", "PageBlob", "AppendBlob"], }, }, copyCompletedOn: { serializedName: "x-ms-copy-completion-time", xmlName: "x-ms-copy-completion-time", type: { name: "DateTimeRfc1123", }, }, copyStatusDescription: { serializedName: "x-ms-copy-status-description", xmlName: "x-ms-copy-status-description", type: { name: "String", }, }, copyId: { serializedName: "x-ms-copy-id", xmlName: "x-ms-copy-id", type: { name: "String", }, }, copyProgress: { serializedName: "x-ms-copy-progress", xmlName: "x-ms-copy-progress", type: { name: "String", }, }, copySource: { serializedName: "x-ms-copy-source", xmlName: "x-ms-copy-source", type: { name: "String", }, }, copyStatus: { serializedName: "x-ms-copy-status", xmlName: "x-ms-copy-status", type: { name: "Enum", allowedValues: ["pending", "success", "aborted", "failed"], }, }, leaseDuration: { serializedName: "x-ms-lease-duration", xmlName: "x-ms-lease-duration", type: { name: "Enum", allowedValues: ["infinite", "fixed"], }, }, leaseState: { serializedName: "x-ms-lease-state", xmlName: "x-ms-lease-state", type: { name: "Enum", allowedValues: [ "available", "leased", "expired", "breaking", "broken", ], }, }, leaseStatus: { serializedName: "x-ms-lease-status", xmlName: "x-ms-lease-status", type: { name: "Enum", allowedValues: ["locked", "unlocked"], }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, isCurrentVersion: { serializedName: "x-ms-is-current-version", xmlName: "x-ms-is-current-version", type: { name: "Boolean", }, }, acceptRanges: { serializedName: "accept-ranges", xmlName: "accept-ranges", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, blobCommittedBlockCount: { serializedName: "x-ms-blob-committed-block-count", xmlName: "x-ms-blob-committed-block-count", type: { name: "Number", }, }, isServerEncrypted: { serializedName: "x-ms-server-encrypted", xmlName: "x-ms-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, blobContentMD5: { serializedName: "x-ms-blob-content-md5", xmlName: "x-ms-blob-content-md5", type: { name: "ByteArray", }, }, tagCount: { serializedName: "x-ms-tag-count", xmlName: "x-ms-tag-count", type: { name: "Number", }, }, isSealed: { serializedName: "x-ms-blob-sealed", xmlName: "x-ms-blob-sealed", type: { name: "Boolean", }, }, lastAccessed: { serializedName: "x-ms-last-access-time", xmlName: "x-ms-last-access-time", type: { name: "DateTimeRfc1123", }, }, immutabilityPolicyExpiresOn: { serializedName: "x-ms-immutability-policy-until-date", xmlName: "x-ms-immutability-policy-until-date", type: { name: "DateTimeRfc1123", }, }, immutabilityPolicyMode: { serializedName: "x-ms-immutability-policy-mode", xmlName: "x-ms-immutability-policy-mode", type: { name: "Enum", allowedValues: ["Mutable", "Unlocked", "Locked"], }, }, legalHold: { serializedName: "x-ms-legal-hold", xmlName: "x-ms-legal-hold", type: { name: "Boolean", }, }, structuredBodyType: { serializedName: "x-ms-structured-body", xmlName: "x-ms-structured-body", type: { name: "String", }, }, structuredContentLength: { serializedName: "x-ms-structured-content-length", xmlName: "x-ms-structured-content-length", type: { name: "Number", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, contentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, }, }, }; const BlobDownloadExceptionHeaders = { serializedName: "Blob_downloadExceptionHeaders", type: { name: "Composite", className: "BlobDownloadExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobGetPropertiesHeaders = { serializedName: "Blob_getPropertiesHeaders", type: { name: "Composite", className: "BlobGetPropertiesHeaders", modelProperties: { lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, createdOn: { serializedName: "x-ms-creation-time", xmlName: "x-ms-creation-time", type: { name: "DateTimeRfc1123", }, }, metadata: { serializedName: "x-ms-meta", headerCollectionPrefix: "x-ms-meta-", xmlName: "x-ms-meta", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, objectReplicationPolicyId: { serializedName: "x-ms-or-policy-id", xmlName: "x-ms-or-policy-id", type: { name: "String", }, }, objectReplicationRules: { serializedName: "x-ms-or", headerCollectionPrefix: "x-ms-or-", xmlName: "x-ms-or", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, blobType: { serializedName: "x-ms-blob-type", xmlName: "x-ms-blob-type", type: { name: "Enum", allowedValues: ["BlockBlob", "PageBlob", "AppendBlob"], }, }, copyCompletedOn: { serializedName: "x-ms-copy-completion-time", xmlName: "x-ms-copy-completion-time", type: { name: "DateTimeRfc1123", }, }, copyStatusDescription: { serializedName: "x-ms-copy-status-description", xmlName: "x-ms-copy-status-description", type: { name: "String", }, }, copyId: { serializedName: "x-ms-copy-id", xmlName: "x-ms-copy-id", type: { name: "String", }, }, copyProgress: { serializedName: "x-ms-copy-progress", xmlName: "x-ms-copy-progress", type: { name: "String", }, }, copySource: { serializedName: "x-ms-copy-source", xmlName: "x-ms-copy-source", type: { name: "String", }, }, copyStatus: { serializedName: "x-ms-copy-status", xmlName: "x-ms-copy-status", type: { name: "Enum", allowedValues: ["pending", "success", "aborted", "failed"], }, }, isIncrementalCopy: { serializedName: "x-ms-incremental-copy", xmlName: "x-ms-incremental-copy", type: { name: "Boolean", }, }, destinationSnapshot: { serializedName: "x-ms-copy-destination-snapshot", xmlName: "x-ms-copy-destination-snapshot", type: { name: "String", }, }, leaseDuration: { serializedName: "x-ms-lease-duration", xmlName: "x-ms-lease-duration", type: { name: "Enum", allowedValues: ["infinite", "fixed"], }, }, leaseState: { serializedName: "x-ms-lease-state", xmlName: "x-ms-lease-state", type: { name: "Enum", allowedValues: [ "available", "leased", "expired", "breaking", "broken", ], }, }, leaseStatus: { serializedName: "x-ms-lease-status", xmlName: "x-ms-lease-status", type: { name: "Enum", allowedValues: ["locked", "unlocked"], }, }, contentLength: { serializedName: "content-length", xmlName: "content-length", type: { name: "Number", }, }, contentType: { serializedName: "content-type", xmlName: "content-type", type: { name: "String", }, }, etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, contentEncoding: { serializedName: "content-encoding", xmlName: "content-encoding", type: { name: "String", }, }, contentDisposition: { serializedName: "content-disposition", xmlName: "content-disposition", type: { name: "String", }, }, contentLanguage: { serializedName: "content-language", xmlName: "content-language", type: { name: "String", }, }, cacheControl: { serializedName: "cache-control", xmlName: "cache-control", type: { name: "String", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, acceptRanges: { serializedName: "accept-ranges", xmlName: "accept-ranges", type: { name: "String", }, }, blobCommittedBlockCount: { serializedName: "x-ms-blob-committed-block-count", xmlName: "x-ms-blob-committed-block-count", type: { name: "Number", }, }, isServerEncrypted: { serializedName: "x-ms-server-encrypted", xmlName: "x-ms-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, accessTier: { serializedName: "x-ms-access-tier", xmlName: "x-ms-access-tier", type: { name: "String", }, }, accessTierInferred: { serializedName: "x-ms-access-tier-inferred", xmlName: "x-ms-access-tier-inferred", type: { name: "Boolean", }, }, archiveStatus: { serializedName: "x-ms-archive-status", xmlName: "x-ms-archive-status", type: { name: "String", }, }, accessTierChangedOn: { serializedName: "x-ms-access-tier-change-time", xmlName: "x-ms-access-tier-change-time", type: { name: "DateTimeRfc1123", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, isCurrentVersion: { serializedName: "x-ms-is-current-version", xmlName: "x-ms-is-current-version", type: { name: "Boolean", }, }, tagCount: { serializedName: "x-ms-tag-count", xmlName: "x-ms-tag-count", type: { name: "Number", }, }, expiresOn: { serializedName: "x-ms-expiry-time", xmlName: "x-ms-expiry-time", type: { name: "DateTimeRfc1123", }, }, isSealed: { serializedName: "x-ms-blob-sealed", xmlName: "x-ms-blob-sealed", type: { name: "Boolean", }, }, rehydratePriority: { serializedName: "x-ms-rehydrate-priority", xmlName: "x-ms-rehydrate-priority", type: { name: "Enum", allowedValues: ["High", "Standard"], }, }, lastAccessed: { serializedName: "x-ms-last-access-time", xmlName: "x-ms-last-access-time", type: { name: "DateTimeRfc1123", }, }, immutabilityPolicyExpiresOn: { serializedName: "x-ms-immutability-policy-until-date", xmlName: "x-ms-immutability-policy-until-date", type: { name: "DateTimeRfc1123", }, }, immutabilityPolicyMode: { serializedName: "x-ms-immutability-policy-mode", xmlName: "x-ms-immutability-policy-mode", type: { name: "Enum", allowedValues: ["Mutable", "Unlocked", "Locked"], }, }, legalHold: { serializedName: "x-ms-legal-hold", xmlName: "x-ms-legal-hold", type: { name: "Boolean", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobGetPropertiesExceptionHeaders = { serializedName: "Blob_getPropertiesExceptionHeaders", type: { name: "Composite", className: "BlobGetPropertiesExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobDeleteHeaders = { serializedName: "Blob_deleteHeaders", type: { name: "Composite", className: "BlobDeleteHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobDeleteExceptionHeaders = { serializedName: "Blob_deleteExceptionHeaders", type: { name: "Composite", className: "BlobDeleteExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobUndeleteHeaders = { serializedName: "Blob_undeleteHeaders", type: { name: "Composite", className: "BlobUndeleteHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobUndeleteExceptionHeaders = { serializedName: "Blob_undeleteExceptionHeaders", type: { name: "Composite", className: "BlobUndeleteExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetExpiryHeaders = { serializedName: "Blob_setExpiryHeaders", type: { name: "Composite", className: "BlobSetExpiryHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const BlobSetExpiryExceptionHeaders = { serializedName: "Blob_setExpiryExceptionHeaders", type: { name: "Composite", className: "BlobSetExpiryExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetHttpHeadersHeaders = { serializedName: "Blob_setHttpHeadersHeaders", type: { name: "Composite", className: "BlobSetHttpHeadersHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetHttpHeadersExceptionHeaders = { serializedName: "Blob_setHttpHeadersExceptionHeaders", type: { name: "Composite", className: "BlobSetHttpHeadersExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetImmutabilityPolicyHeaders = { serializedName: "Blob_setImmutabilityPolicyHeaders", type: { name: "Composite", className: "BlobSetImmutabilityPolicyHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, immutabilityPolicyExpiry: { serializedName: "x-ms-immutability-policy-until-date", xmlName: "x-ms-immutability-policy-until-date", type: { name: "DateTimeRfc1123", }, }, immutabilityPolicyMode: { serializedName: "x-ms-immutability-policy-mode", xmlName: "x-ms-immutability-policy-mode", type: { name: "Enum", allowedValues: ["Mutable", "Unlocked", "Locked"], }, }, }, }, }; const BlobSetImmutabilityPolicyExceptionHeaders = { serializedName: "Blob_setImmutabilityPolicyExceptionHeaders", type: { name: "Composite", className: "BlobSetImmutabilityPolicyExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobDeleteImmutabilityPolicyHeaders = { serializedName: "Blob_deleteImmutabilityPolicyHeaders", type: { name: "Composite", className: "BlobDeleteImmutabilityPolicyHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const BlobDeleteImmutabilityPolicyExceptionHeaders = { serializedName: "Blob_deleteImmutabilityPolicyExceptionHeaders", type: { name: "Composite", className: "BlobDeleteImmutabilityPolicyExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetLegalHoldHeaders = { serializedName: "Blob_setLegalHoldHeaders", type: { name: "Composite", className: "BlobSetLegalHoldHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, legalHold: { serializedName: "x-ms-legal-hold", xmlName: "x-ms-legal-hold", type: { name: "Boolean", }, }, }, }, }; const BlobSetLegalHoldExceptionHeaders = { serializedName: "Blob_setLegalHoldExceptionHeaders", type: { name: "Composite", className: "BlobSetLegalHoldExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetMetadataHeaders = { serializedName: "Blob_setMetadataHeaders", type: { name: "Composite", className: "BlobSetMetadataHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetMetadataExceptionHeaders = { serializedName: "Blob_setMetadataExceptionHeaders", type: { name: "Composite", className: "BlobSetMetadataExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobAcquireLeaseHeaders = { serializedName: "Blob_acquireLeaseHeaders", type: { name: "Composite", className: "BlobAcquireLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, leaseId: { serializedName: "x-ms-lease-id", xmlName: "x-ms-lease-id", type: { name: "String", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const BlobAcquireLeaseExceptionHeaders = { serializedName: "Blob_acquireLeaseExceptionHeaders", type: { name: "Composite", className: "BlobAcquireLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobReleaseLeaseHeaders = { serializedName: "Blob_releaseLeaseHeaders", type: { name: "Composite", className: "BlobReleaseLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const BlobReleaseLeaseExceptionHeaders = { serializedName: "Blob_releaseLeaseExceptionHeaders", type: { name: "Composite", className: "BlobReleaseLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobRenewLeaseHeaders = { serializedName: "Blob_renewLeaseHeaders", type: { name: "Composite", className: "BlobRenewLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, leaseId: { serializedName: "x-ms-lease-id", xmlName: "x-ms-lease-id", type: { name: "String", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const BlobRenewLeaseExceptionHeaders = { serializedName: "Blob_renewLeaseExceptionHeaders", type: { name: "Composite", className: "BlobRenewLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobChangeLeaseHeaders = { serializedName: "Blob_changeLeaseHeaders", type: { name: "Composite", className: "BlobChangeLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, leaseId: { serializedName: "x-ms-lease-id", xmlName: "x-ms-lease-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const BlobChangeLeaseExceptionHeaders = { serializedName: "Blob_changeLeaseExceptionHeaders", type: { name: "Composite", className: "BlobChangeLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobBreakLeaseHeaders = { serializedName: "Blob_breakLeaseHeaders", type: { name: "Composite", className: "BlobBreakLeaseHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, leaseTime: { serializedName: "x-ms-lease-time", xmlName: "x-ms-lease-time", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, }, }, }; const BlobBreakLeaseExceptionHeaders = { serializedName: "Blob_breakLeaseExceptionHeaders", type: { name: "Composite", className: "BlobBreakLeaseExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobCreateSnapshotHeaders = { serializedName: "Blob_createSnapshotHeaders", type: { name: "Composite", className: "BlobCreateSnapshotHeaders", modelProperties: { snapshot: { serializedName: "x-ms-snapshot", xmlName: "x-ms-snapshot", type: { name: "String", }, }, etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobCreateSnapshotExceptionHeaders = { serializedName: "Blob_createSnapshotExceptionHeaders", type: { name: "Composite", className: "BlobCreateSnapshotExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobStartCopyFromURLHeaders = { serializedName: "Blob_startCopyFromURLHeaders", type: { name: "Composite", className: "BlobStartCopyFromURLHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, copyId: { serializedName: "x-ms-copy-id", xmlName: "x-ms-copy-id", type: { name: "String", }, }, copyStatus: { serializedName: "x-ms-copy-status", xmlName: "x-ms-copy-status", type: { name: "Enum", allowedValues: ["pending", "success", "aborted", "failed"], }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobStartCopyFromURLExceptionHeaders = { serializedName: "Blob_startCopyFromURLExceptionHeaders", type: { name: "Composite", className: "BlobStartCopyFromURLExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, copySourceErrorCode: { serializedName: "x-ms-copy-source-error-code", xmlName: "x-ms-copy-source-error-code", type: { name: "String", }, }, copySourceStatusCode: { serializedName: "x-ms-copy-source-status-code", xmlName: "x-ms-copy-source-status-code", type: { name: "Number", }, }, }, }, }; const BlobCopyFromURLHeaders = { serializedName: "Blob_copyFromURLHeaders", type: { name: "Composite", className: "BlobCopyFromURLHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, copyId: { serializedName: "x-ms-copy-id", xmlName: "x-ms-copy-id", type: { name: "String", }, }, copyStatus: { defaultValue: "success", isConstant: true, serializedName: "x-ms-copy-status", type: { name: "String", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, xMsContentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobCopyFromURLExceptionHeaders = { serializedName: "Blob_copyFromURLExceptionHeaders", type: { name: "Composite", className: "BlobCopyFromURLExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, copySourceErrorCode: { serializedName: "x-ms-copy-source-error-code", xmlName: "x-ms-copy-source-error-code", type: { name: "String", }, }, copySourceStatusCode: { serializedName: "x-ms-copy-source-status-code", xmlName: "x-ms-copy-source-status-code", type: { name: "Number", }, }, }, }, }; const BlobAbortCopyFromURLHeaders = { serializedName: "Blob_abortCopyFromURLHeaders", type: { name: "Composite", className: "BlobAbortCopyFromURLHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobAbortCopyFromURLExceptionHeaders = { serializedName: "Blob_abortCopyFromURLExceptionHeaders", type: { name: "Composite", className: "BlobAbortCopyFromURLExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetTierHeaders = { serializedName: "Blob_setTierHeaders", type: { name: "Composite", className: "BlobSetTierHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetTierExceptionHeaders = { serializedName: "Blob_setTierExceptionHeaders", type: { name: "Composite", className: "BlobSetTierExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobGetAccountInfoHeaders = { serializedName: "Blob_getAccountInfoHeaders", type: { name: "Composite", className: "BlobGetAccountInfoHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, skuName: { serializedName: "x-ms-sku-name", xmlName: "x-ms-sku-name", type: { name: "Enum", allowedValues: [ "Standard_LRS", "Standard_GRS", "Standard_RAGRS", "Standard_ZRS", "Premium_LRS", "Standard_GZRS", "Premium_ZRS", "Standard_RAGZRS", ], }, }, accountKind: { serializedName: "x-ms-account-kind", xmlName: "x-ms-account-kind", type: { name: "Enum", allowedValues: [ "Storage", "BlobStorage", "StorageV2", "FileStorage", "BlockBlobStorage", ], }, }, isHierarchicalNamespaceEnabled: { serializedName: "x-ms-is-hns-enabled", xmlName: "x-ms-is-hns-enabled", type: { name: "Boolean", }, }, }, }, }; const BlobGetAccountInfoExceptionHeaders = { serializedName: "Blob_getAccountInfoExceptionHeaders", type: { name: "Composite", className: "BlobGetAccountInfoExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobQueryHeaders = { serializedName: "Blob_queryHeaders", type: { name: "Composite", className: "BlobQueryHeaders", modelProperties: { lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, metadata: { serializedName: "x-ms-meta", headerCollectionPrefix: "x-ms-meta-", xmlName: "x-ms-meta", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, contentLength: { serializedName: "content-length", xmlName: "content-length", type: { name: "Number", }, }, contentType: { serializedName: "content-type", xmlName: "content-type", type: { name: "String", }, }, contentRange: { serializedName: "content-range", xmlName: "content-range", type: { name: "String", }, }, etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, contentEncoding: { serializedName: "content-encoding", xmlName: "content-encoding", type: { name: "String", }, }, cacheControl: { serializedName: "cache-control", xmlName: "cache-control", type: { name: "String", }, }, contentDisposition: { serializedName: "content-disposition", xmlName: "content-disposition", type: { name: "String", }, }, contentLanguage: { serializedName: "content-language", xmlName: "content-language", type: { name: "String", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, blobType: { serializedName: "x-ms-blob-type", xmlName: "x-ms-blob-type", type: { name: "Enum", allowedValues: ["BlockBlob", "PageBlob", "AppendBlob"], }, }, copyCompletionTime: { serializedName: "x-ms-copy-completion-time", xmlName: "x-ms-copy-completion-time", type: { name: "DateTimeRfc1123", }, }, copyStatusDescription: { serializedName: "x-ms-copy-status-description", xmlName: "x-ms-copy-status-description", type: { name: "String", }, }, copyId: { serializedName: "x-ms-copy-id", xmlName: "x-ms-copy-id", type: { name: "String", }, }, copyProgress: { serializedName: "x-ms-copy-progress", xmlName: "x-ms-copy-progress", type: { name: "String", }, }, copySource: { serializedName: "x-ms-copy-source", xmlName: "x-ms-copy-source", type: { name: "String", }, }, copyStatus: { serializedName: "x-ms-copy-status", xmlName: "x-ms-copy-status", type: { name: "Enum", allowedValues: ["pending", "success", "aborted", "failed"], }, }, leaseDuration: { serializedName: "x-ms-lease-duration", xmlName: "x-ms-lease-duration", type: { name: "Enum", allowedValues: ["infinite", "fixed"], }, }, leaseState: { serializedName: "x-ms-lease-state", xmlName: "x-ms-lease-state", type: { name: "Enum", allowedValues: [ "available", "leased", "expired", "breaking", "broken", ], }, }, leaseStatus: { serializedName: "x-ms-lease-status", xmlName: "x-ms-lease-status", type: { name: "Enum", allowedValues: ["locked", "unlocked"], }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, acceptRanges: { serializedName: "accept-ranges", xmlName: "accept-ranges", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, blobCommittedBlockCount: { serializedName: "x-ms-blob-committed-block-count", xmlName: "x-ms-blob-committed-block-count", type: { name: "Number", }, }, isServerEncrypted: { serializedName: "x-ms-server-encrypted", xmlName: "x-ms-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, blobContentMD5: { serializedName: "x-ms-blob-content-md5", xmlName: "x-ms-blob-content-md5", type: { name: "ByteArray", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, contentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, }, }, }; const BlobQueryExceptionHeaders = { serializedName: "Blob_queryExceptionHeaders", type: { name: "Composite", className: "BlobQueryExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobGetTagsHeaders = { serializedName: "Blob_getTagsHeaders", type: { name: "Composite", className: "BlobGetTagsHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobGetTagsExceptionHeaders = { serializedName: "Blob_getTagsExceptionHeaders", type: { name: "Composite", className: "BlobGetTagsExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetTagsHeaders = { serializedName: "Blob_setTagsHeaders", type: { name: "Composite", className: "BlobSetTagsHeaders", modelProperties: { clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlobSetTagsExceptionHeaders = { serializedName: "Blob_setTagsExceptionHeaders", type: { name: "Composite", className: "BlobSetTagsExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobCreateHeaders = { serializedName: "PageBlob_createHeaders", type: { name: "Composite", className: "PageBlobCreateHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobCreateExceptionHeaders = { serializedName: "PageBlob_createExceptionHeaders", type: { name: "Composite", className: "PageBlobCreateExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobUploadPagesHeaders = { serializedName: "PageBlob_uploadPagesHeaders", type: { name: "Composite", className: "PageBlobUploadPagesHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, xMsContentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, structuredBodyType: { serializedName: "x-ms-structured-body", xmlName: "x-ms-structured-body", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobUploadPagesExceptionHeaders = { serializedName: "PageBlob_uploadPagesExceptionHeaders", type: { name: "Composite", className: "PageBlobUploadPagesExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobClearPagesHeaders = { serializedName: "PageBlob_clearPagesHeaders", type: { name: "Composite", className: "PageBlobClearPagesHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, xMsContentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobClearPagesExceptionHeaders = { serializedName: "PageBlob_clearPagesExceptionHeaders", type: { name: "Composite", className: "PageBlobClearPagesExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobUploadPagesFromURLHeaders = { serializedName: "PageBlob_uploadPagesFromURLHeaders", type: { name: "Composite", className: "PageBlobUploadPagesFromURLHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, xMsContentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobUploadPagesFromURLExceptionHeaders = { serializedName: "PageBlob_uploadPagesFromURLExceptionHeaders", type: { name: "Composite", className: "PageBlobUploadPagesFromURLExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, copySourceErrorCode: { serializedName: "x-ms-copy-source-error-code", xmlName: "x-ms-copy-source-error-code", type: { name: "String", }, }, copySourceStatusCode: { serializedName: "x-ms-copy-source-status-code", xmlName: "x-ms-copy-source-status-code", type: { name: "Number", }, }, }, }, }; const PageBlobGetPageRangesHeaders = { serializedName: "PageBlob_getPageRangesHeaders", type: { name: "Composite", className: "PageBlobGetPageRangesHeaders", modelProperties: { lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, blobContentLength: { serializedName: "x-ms-blob-content-length", xmlName: "x-ms-blob-content-length", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobGetPageRangesExceptionHeaders = { serializedName: "PageBlob_getPageRangesExceptionHeaders", type: { name: "Composite", className: "PageBlobGetPageRangesExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobGetPageRangesDiffHeaders = { serializedName: "PageBlob_getPageRangesDiffHeaders", type: { name: "Composite", className: "PageBlobGetPageRangesDiffHeaders", modelProperties: { lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, blobContentLength: { serializedName: "x-ms-blob-content-length", xmlName: "x-ms-blob-content-length", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobGetPageRangesDiffExceptionHeaders = { serializedName: "PageBlob_getPageRangesDiffExceptionHeaders", type: { name: "Composite", className: "PageBlobGetPageRangesDiffExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobResizeHeaders = { serializedName: "PageBlob_resizeHeaders", type: { name: "Composite", className: "PageBlobResizeHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobResizeExceptionHeaders = { serializedName: "PageBlob_resizeExceptionHeaders", type: { name: "Composite", className: "PageBlobResizeExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobUpdateSequenceNumberHeaders = { serializedName: "PageBlob_updateSequenceNumberHeaders", type: { name: "Composite", className: "PageBlobUpdateSequenceNumberHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, blobSequenceNumber: { serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobUpdateSequenceNumberExceptionHeaders = { serializedName: "PageBlob_updateSequenceNumberExceptionHeaders", type: { name: "Composite", className: "PageBlobUpdateSequenceNumberExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobCopyIncrementalHeaders = { serializedName: "PageBlob_copyIncrementalHeaders", type: { name: "Composite", className: "PageBlobCopyIncrementalHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, copyId: { serializedName: "x-ms-copy-id", xmlName: "x-ms-copy-id", type: { name: "String", }, }, copyStatus: { serializedName: "x-ms-copy-status", xmlName: "x-ms-copy-status", type: { name: "Enum", allowedValues: ["pending", "success", "aborted", "failed"], }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const PageBlobCopyIncrementalExceptionHeaders = { serializedName: "PageBlob_copyIncrementalExceptionHeaders", type: { name: "Composite", className: "PageBlobCopyIncrementalExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const AppendBlobCreateHeaders = { serializedName: "AppendBlob_createHeaders", type: { name: "Composite", className: "AppendBlobCreateHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const AppendBlobCreateExceptionHeaders = { serializedName: "AppendBlob_createExceptionHeaders", type: { name: "Composite", className: "AppendBlobCreateExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const AppendBlobAppendBlockHeaders = { serializedName: "AppendBlob_appendBlockHeaders", type: { name: "Composite", className: "AppendBlobAppendBlockHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, xMsContentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, blobAppendOffset: { serializedName: "x-ms-blob-append-offset", xmlName: "x-ms-blob-append-offset", type: { name: "String", }, }, blobCommittedBlockCount: { serializedName: "x-ms-blob-committed-block-count", xmlName: "x-ms-blob-committed-block-count", type: { name: "Number", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, structuredBodyType: { serializedName: "x-ms-structured-body", xmlName: "x-ms-structured-body", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const AppendBlobAppendBlockExceptionHeaders = { serializedName: "AppendBlob_appendBlockExceptionHeaders", type: { name: "Composite", className: "AppendBlobAppendBlockExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const AppendBlobAppendBlockFromUrlHeaders = { serializedName: "AppendBlob_appendBlockFromUrlHeaders", type: { name: "Composite", className: "AppendBlobAppendBlockFromUrlHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, xMsContentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, blobAppendOffset: { serializedName: "x-ms-blob-append-offset", xmlName: "x-ms-blob-append-offset", type: { name: "String", }, }, blobCommittedBlockCount: { serializedName: "x-ms-blob-committed-block-count", xmlName: "x-ms-blob-committed-block-count", type: { name: "Number", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const AppendBlobAppendBlockFromUrlExceptionHeaders = { serializedName: "AppendBlob_appendBlockFromUrlExceptionHeaders", type: { name: "Composite", className: "AppendBlobAppendBlockFromUrlExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, copySourceErrorCode: { serializedName: "x-ms-copy-source-error-code", xmlName: "x-ms-copy-source-error-code", type: { name: "String", }, }, copySourceStatusCode: { serializedName: "x-ms-copy-source-status-code", xmlName: "x-ms-copy-source-status-code", type: { name: "Number", }, }, }, }, }; const AppendBlobSealHeaders = { serializedName: "AppendBlob_sealHeaders", type: { name: "Composite", className: "AppendBlobSealHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isSealed: { serializedName: "x-ms-blob-sealed", xmlName: "x-ms-blob-sealed", type: { name: "Boolean", }, }, }, }, }; const AppendBlobSealExceptionHeaders = { serializedName: "AppendBlob_sealExceptionHeaders", type: { name: "Composite", className: "AppendBlobSealExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobUploadHeaders = { serializedName: "BlockBlob_uploadHeaders", type: { name: "Composite", className: "BlockBlobUploadHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, structuredBodyType: { serializedName: "x-ms-structured-body", xmlName: "x-ms-structured-body", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobUploadExceptionHeaders = { serializedName: "BlockBlob_uploadExceptionHeaders", type: { name: "Composite", className: "BlockBlobUploadExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobPutBlobFromUrlHeaders = { serializedName: "BlockBlob_putBlobFromUrlHeaders", type: { name: "Composite", className: "BlockBlobPutBlobFromUrlHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobPutBlobFromUrlExceptionHeaders = { serializedName: "BlockBlob_putBlobFromUrlExceptionHeaders", type: { name: "Composite", className: "BlockBlobPutBlobFromUrlExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, copySourceErrorCode: { serializedName: "x-ms-copy-source-error-code", xmlName: "x-ms-copy-source-error-code", type: { name: "String", }, }, copySourceStatusCode: { serializedName: "x-ms-copy-source-status-code", xmlName: "x-ms-copy-source-status-code", type: { name: "Number", }, }, }, }, }; const BlockBlobStageBlockHeaders = { serializedName: "BlockBlob_stageBlockHeaders", type: { name: "Composite", className: "BlockBlobStageBlockHeaders", modelProperties: { contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, xMsContentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, structuredBodyType: { serializedName: "x-ms-structured-body", xmlName: "x-ms-structured-body", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobStageBlockExceptionHeaders = { serializedName: "BlockBlob_stageBlockExceptionHeaders", type: { name: "Composite", className: "BlockBlobStageBlockExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobStageBlockFromURLHeaders = { serializedName: "BlockBlob_stageBlockFromURLHeaders", type: { name: "Composite", className: "BlockBlobStageBlockFromURLHeaders", modelProperties: { contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, xMsContentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobStageBlockFromURLExceptionHeaders = { serializedName: "BlockBlob_stageBlockFromURLExceptionHeaders", type: { name: "Composite", className: "BlockBlobStageBlockFromURLExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, copySourceErrorCode: { serializedName: "x-ms-copy-source-error-code", xmlName: "x-ms-copy-source-error-code", type: { name: "String", }, }, copySourceStatusCode: { serializedName: "x-ms-copy-source-status-code", xmlName: "x-ms-copy-source-status-code", type: { name: "Number", }, }, }, }, }; const BlockBlobCommitBlockListHeaders = { serializedName: "BlockBlob_commitBlockListHeaders", type: { name: "Composite", className: "BlockBlobCommitBlockListHeaders", modelProperties: { etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, contentMD5: { serializedName: "content-md5", xmlName: "content-md5", type: { name: "ByteArray", }, }, xMsContentCrc64: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, versionId: { serializedName: "x-ms-version-id", xmlName: "x-ms-version-id", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, isServerEncrypted: { serializedName: "x-ms-request-server-encrypted", xmlName: "x-ms-request-server-encrypted", type: { name: "Boolean", }, }, encryptionKeySha256: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, encryptionScope: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobCommitBlockListExceptionHeaders = { serializedName: "BlockBlob_commitBlockListExceptionHeaders", type: { name: "Composite", className: "BlockBlobCommitBlockListExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobGetBlockListHeaders = { serializedName: "BlockBlob_getBlockListHeaders", type: { name: "Composite", className: "BlockBlobGetBlockListHeaders", modelProperties: { lastModified: { serializedName: "last-modified", xmlName: "last-modified", type: { name: "DateTimeRfc1123", }, }, etag: { serializedName: "etag", xmlName: "etag", type: { name: "String", }, }, contentType: { serializedName: "content-type", xmlName: "content-type", type: { name: "String", }, }, blobContentLength: { serializedName: "x-ms-blob-content-length", xmlName: "x-ms-blob-content-length", type: { name: "Number", }, }, clientRequestId: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, requestId: { serializedName: "x-ms-request-id", xmlName: "x-ms-request-id", type: { name: "String", }, }, version: { serializedName: "x-ms-version", xmlName: "x-ms-version", type: { name: "String", }, }, date: { serializedName: "date", xmlName: "date", type: { name: "DateTimeRfc1123", }, }, errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; const BlockBlobGetBlockListExceptionHeaders = { serializedName: "BlockBlob_getBlockListExceptionHeaders", type: { name: "Composite", className: "BlockBlobGetBlockListExceptionHeaders", modelProperties: { errorCode: { serializedName: "x-ms-error-code", xmlName: "x-ms-error-code", type: { name: "String", }, }, }, }, }; var Mappers = /*#__PURE__*/Object.freeze({ __proto__: null, AccessPolicy: AccessPolicy, AppendBlobAppendBlockExceptionHeaders: AppendBlobAppendBlockExceptionHeaders, AppendBlobAppendBlockFromUrlExceptionHeaders: AppendBlobAppendBlockFromUrlExceptionHeaders, AppendBlobAppendBlockFromUrlHeaders: AppendBlobAppendBlockFromUrlHeaders, AppendBlobAppendBlockHeaders: AppendBlobAppendBlockHeaders, AppendBlobCreateExceptionHeaders: AppendBlobCreateExceptionHeaders, AppendBlobCreateHeaders: AppendBlobCreateHeaders, AppendBlobSealExceptionHeaders: AppendBlobSealExceptionHeaders, AppendBlobSealHeaders: AppendBlobSealHeaders, ArrowConfiguration: ArrowConfiguration, ArrowField: ArrowField, BlobAbortCopyFromURLExceptionHeaders: BlobAbortCopyFromURLExceptionHeaders, BlobAbortCopyFromURLHeaders: BlobAbortCopyFromURLHeaders, BlobAcquireLeaseExceptionHeaders: BlobAcquireLeaseExceptionHeaders, BlobAcquireLeaseHeaders: BlobAcquireLeaseHeaders, BlobBreakLeaseExceptionHeaders: BlobBreakLeaseExceptionHeaders, BlobBreakLeaseHeaders: BlobBreakLeaseHeaders, BlobChangeLeaseExceptionHeaders: BlobChangeLeaseExceptionHeaders, BlobChangeLeaseHeaders: BlobChangeLeaseHeaders, BlobCopyFromURLExceptionHeaders: BlobCopyFromURLExceptionHeaders, BlobCopyFromURLHeaders: BlobCopyFromURLHeaders, BlobCreateSnapshotExceptionHeaders: BlobCreateSnapshotExceptionHeaders, BlobCreateSnapshotHeaders: BlobCreateSnapshotHeaders, BlobDeleteExceptionHeaders: BlobDeleteExceptionHeaders, BlobDeleteHeaders: BlobDeleteHeaders, BlobDeleteImmutabilityPolicyExceptionHeaders: BlobDeleteImmutabilityPolicyExceptionHeaders, BlobDeleteImmutabilityPolicyHeaders: BlobDeleteImmutabilityPolicyHeaders, BlobDownloadExceptionHeaders: BlobDownloadExceptionHeaders, BlobDownloadHeaders: BlobDownloadHeaders, BlobFlatListSegment: BlobFlatListSegment, BlobGetAccountInfoExceptionHeaders: BlobGetAccountInfoExceptionHeaders, BlobGetAccountInfoHeaders: BlobGetAccountInfoHeaders, BlobGetPropertiesExceptionHeaders: BlobGetPropertiesExceptionHeaders, BlobGetPropertiesHeaders: BlobGetPropertiesHeaders, BlobGetTagsExceptionHeaders: BlobGetTagsExceptionHeaders, BlobGetTagsHeaders: BlobGetTagsHeaders, BlobHierarchyListSegment: BlobHierarchyListSegment, BlobItemInternal: BlobItemInternal, BlobName: BlobName, BlobPrefix: BlobPrefix, BlobPropertiesInternal: BlobPropertiesInternal, BlobQueryExceptionHeaders: BlobQueryExceptionHeaders, BlobQueryHeaders: BlobQueryHeaders, BlobReleaseLeaseExceptionHeaders: BlobReleaseLeaseExceptionHeaders, BlobReleaseLeaseHeaders: BlobReleaseLeaseHeaders, BlobRenewLeaseExceptionHeaders: BlobRenewLeaseExceptionHeaders, BlobRenewLeaseHeaders: BlobRenewLeaseHeaders, BlobServiceProperties: BlobServiceProperties, BlobServiceStatistics: BlobServiceStatistics, BlobSetExpiryExceptionHeaders: BlobSetExpiryExceptionHeaders, BlobSetExpiryHeaders: BlobSetExpiryHeaders, BlobSetHttpHeadersExceptionHeaders: BlobSetHttpHeadersExceptionHeaders, BlobSetHttpHeadersHeaders: BlobSetHttpHeadersHeaders, BlobSetImmutabilityPolicyExceptionHeaders: BlobSetImmutabilityPolicyExceptionHeaders, BlobSetImmutabilityPolicyHeaders: BlobSetImmutabilityPolicyHeaders, BlobSetLegalHoldExceptionHeaders: BlobSetLegalHoldExceptionHeaders, BlobSetLegalHoldHeaders: BlobSetLegalHoldHeaders, BlobSetMetadataExceptionHeaders: BlobSetMetadataExceptionHeaders, BlobSetMetadataHeaders: BlobSetMetadataHeaders, BlobSetTagsExceptionHeaders: BlobSetTagsExceptionHeaders, BlobSetTagsHeaders: BlobSetTagsHeaders, BlobSetTierExceptionHeaders: BlobSetTierExceptionHeaders, BlobSetTierHeaders: BlobSetTierHeaders, BlobStartCopyFromURLExceptionHeaders: BlobStartCopyFromURLExceptionHeaders, BlobStartCopyFromURLHeaders: BlobStartCopyFromURLHeaders, BlobTag: BlobTag, BlobTags: BlobTags, BlobUndeleteExceptionHeaders: BlobUndeleteExceptionHeaders, BlobUndeleteHeaders: BlobUndeleteHeaders, Block: Block, BlockBlobCommitBlockListExceptionHeaders: BlockBlobCommitBlockListExceptionHeaders, BlockBlobCommitBlockListHeaders: BlockBlobCommitBlockListHeaders, BlockBlobGetBlockListExceptionHeaders: BlockBlobGetBlockListExceptionHeaders, BlockBlobGetBlockListHeaders: BlockBlobGetBlockListHeaders, BlockBlobPutBlobFromUrlExceptionHeaders: BlockBlobPutBlobFromUrlExceptionHeaders, BlockBlobPutBlobFromUrlHeaders: BlockBlobPutBlobFromUrlHeaders, BlockBlobStageBlockExceptionHeaders: BlockBlobStageBlockExceptionHeaders, BlockBlobStageBlockFromURLExceptionHeaders: BlockBlobStageBlockFromURLExceptionHeaders, BlockBlobStageBlockFromURLHeaders: BlockBlobStageBlockFromURLHeaders, BlockBlobStageBlockHeaders: BlockBlobStageBlockHeaders, BlockBlobUploadExceptionHeaders: BlockBlobUploadExceptionHeaders, BlockBlobUploadHeaders: BlockBlobUploadHeaders, BlockList: BlockList, BlockLookupList: BlockLookupList, ClearRange: ClearRange, ContainerAcquireLeaseExceptionHeaders: ContainerAcquireLeaseExceptionHeaders, ContainerAcquireLeaseHeaders: ContainerAcquireLeaseHeaders, ContainerBreakLeaseExceptionHeaders: ContainerBreakLeaseExceptionHeaders, ContainerBreakLeaseHeaders: ContainerBreakLeaseHeaders, ContainerChangeLeaseExceptionHeaders: ContainerChangeLeaseExceptionHeaders, ContainerChangeLeaseHeaders: ContainerChangeLeaseHeaders, ContainerCreateExceptionHeaders: ContainerCreateExceptionHeaders, ContainerCreateHeaders: ContainerCreateHeaders, ContainerDeleteExceptionHeaders: ContainerDeleteExceptionHeaders, ContainerDeleteHeaders: ContainerDeleteHeaders, ContainerFilterBlobsExceptionHeaders: ContainerFilterBlobsExceptionHeaders, ContainerFilterBlobsHeaders: ContainerFilterBlobsHeaders, ContainerGetAccessPolicyExceptionHeaders: ContainerGetAccessPolicyExceptionHeaders, ContainerGetAccessPolicyHeaders: ContainerGetAccessPolicyHeaders, ContainerGetAccountInfoExceptionHeaders: ContainerGetAccountInfoExceptionHeaders, ContainerGetAccountInfoHeaders: ContainerGetAccountInfoHeaders, ContainerGetPropertiesExceptionHeaders: ContainerGetPropertiesExceptionHeaders, ContainerGetPropertiesHeaders: ContainerGetPropertiesHeaders, ContainerItem: ContainerItem, ContainerListBlobFlatSegmentExceptionHeaders: ContainerListBlobFlatSegmentExceptionHeaders, ContainerListBlobFlatSegmentHeaders: ContainerListBlobFlatSegmentHeaders, ContainerListBlobHierarchySegmentExceptionHeaders: ContainerListBlobHierarchySegmentExceptionHeaders, ContainerListBlobHierarchySegmentHeaders: ContainerListBlobHierarchySegmentHeaders, ContainerProperties: ContainerProperties, ContainerReleaseLeaseExceptionHeaders: ContainerReleaseLeaseExceptionHeaders, ContainerReleaseLeaseHeaders: ContainerReleaseLeaseHeaders, ContainerRenameExceptionHeaders: ContainerRenameExceptionHeaders, ContainerRenameHeaders: ContainerRenameHeaders, ContainerRenewLeaseExceptionHeaders: ContainerRenewLeaseExceptionHeaders, ContainerRenewLeaseHeaders: ContainerRenewLeaseHeaders, ContainerRestoreExceptionHeaders: ContainerRestoreExceptionHeaders, ContainerRestoreHeaders: ContainerRestoreHeaders, ContainerSetAccessPolicyExceptionHeaders: ContainerSetAccessPolicyExceptionHeaders, ContainerSetAccessPolicyHeaders: ContainerSetAccessPolicyHeaders, ContainerSetMetadataExceptionHeaders: ContainerSetMetadataExceptionHeaders, ContainerSetMetadataHeaders: ContainerSetMetadataHeaders, ContainerSubmitBatchExceptionHeaders: ContainerSubmitBatchExceptionHeaders, ContainerSubmitBatchHeaders: ContainerSubmitBatchHeaders, CorsRule: CorsRule, DelimitedTextConfiguration: DelimitedTextConfiguration, FilterBlobItem: FilterBlobItem, FilterBlobSegment: FilterBlobSegment, GeoReplication: GeoReplication, JsonTextConfiguration: JsonTextConfiguration, KeyInfo: KeyInfo, ListBlobsFlatSegmentResponse: ListBlobsFlatSegmentResponse, ListBlobsHierarchySegmentResponse: ListBlobsHierarchySegmentResponse, ListContainersSegmentResponse: ListContainersSegmentResponse, Logging: Logging, Metrics: Metrics, PageBlobClearPagesExceptionHeaders: PageBlobClearPagesExceptionHeaders, PageBlobClearPagesHeaders: PageBlobClearPagesHeaders, PageBlobCopyIncrementalExceptionHeaders: PageBlobCopyIncrementalExceptionHeaders, PageBlobCopyIncrementalHeaders: PageBlobCopyIncrementalHeaders, PageBlobCreateExceptionHeaders: PageBlobCreateExceptionHeaders, PageBlobCreateHeaders: PageBlobCreateHeaders, PageBlobGetPageRangesDiffExceptionHeaders: PageBlobGetPageRangesDiffExceptionHeaders, PageBlobGetPageRangesDiffHeaders: PageBlobGetPageRangesDiffHeaders, PageBlobGetPageRangesExceptionHeaders: PageBlobGetPageRangesExceptionHeaders, PageBlobGetPageRangesHeaders: PageBlobGetPageRangesHeaders, PageBlobResizeExceptionHeaders: PageBlobResizeExceptionHeaders, PageBlobResizeHeaders: PageBlobResizeHeaders, PageBlobUpdateSequenceNumberExceptionHeaders: PageBlobUpdateSequenceNumberExceptionHeaders, PageBlobUpdateSequenceNumberHeaders: PageBlobUpdateSequenceNumberHeaders, PageBlobUploadPagesExceptionHeaders: PageBlobUploadPagesExceptionHeaders, PageBlobUploadPagesFromURLExceptionHeaders: PageBlobUploadPagesFromURLExceptionHeaders, PageBlobUploadPagesFromURLHeaders: PageBlobUploadPagesFromURLHeaders, PageBlobUploadPagesHeaders: PageBlobUploadPagesHeaders, PageList: PageList, PageRange: PageRange, QueryFormat: QueryFormat, QueryRequest: QueryRequest, QuerySerialization: QuerySerialization, RetentionPolicy: RetentionPolicy, ServiceFilterBlobsExceptionHeaders: ServiceFilterBlobsExceptionHeaders, ServiceFilterBlobsHeaders: ServiceFilterBlobsHeaders, ServiceGetAccountInfoExceptionHeaders: ServiceGetAccountInfoExceptionHeaders, ServiceGetAccountInfoHeaders: ServiceGetAccountInfoHeaders, ServiceGetPropertiesExceptionHeaders: ServiceGetPropertiesExceptionHeaders, ServiceGetPropertiesHeaders: ServiceGetPropertiesHeaders, ServiceGetStatisticsExceptionHeaders: ServiceGetStatisticsExceptionHeaders, ServiceGetStatisticsHeaders: ServiceGetStatisticsHeaders, ServiceGetUserDelegationKeyExceptionHeaders: ServiceGetUserDelegationKeyExceptionHeaders, ServiceGetUserDelegationKeyHeaders: ServiceGetUserDelegationKeyHeaders, ServiceListContainersSegmentExceptionHeaders: ServiceListContainersSegmentExceptionHeaders, ServiceListContainersSegmentHeaders: ServiceListContainersSegmentHeaders, ServiceSetPropertiesExceptionHeaders: ServiceSetPropertiesExceptionHeaders, ServiceSetPropertiesHeaders: ServiceSetPropertiesHeaders, ServiceSubmitBatchExceptionHeaders: ServiceSubmitBatchExceptionHeaders, ServiceSubmitBatchHeaders: ServiceSubmitBatchHeaders, SignedIdentifier: SignedIdentifier, StaticWebsite: StaticWebsite, StorageError: StorageError, UserDelegationKey: UserDelegationKey }); /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ const contentType = { parameterPath: ["options", "contentType"], mapper: { defaultValue: "application/xml", isConstant: true, serializedName: "Content-Type", type: { name: "String", }, }, }; const blobServiceProperties = { parameterPath: "blobServiceProperties", mapper: BlobServiceProperties, }; const accept = { parameterPath: "accept", mapper: { defaultValue: "application/xml", isConstant: true, serializedName: "Accept", type: { name: "String", }, }, }; const url = { parameterPath: "url", mapper: { serializedName: "url", required: true, xmlName: "url", type: { name: "String", }, }, skipEncoding: true, }; const restype = { parameterPath: "restype", mapper: { defaultValue: "service", isConstant: true, serializedName: "restype", type: { name: "String", }, }, }; const comp = { parameterPath: "comp", mapper: { defaultValue: "properties", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const timeoutInSeconds = { parameterPath: ["options", "timeoutInSeconds"], mapper: { constraints: { InclusiveMinimum: 0, }, serializedName: "timeout", xmlName: "timeout", type: { name: "Number", }, }, }; const version$1 = { parameterPath: "version", mapper: { defaultValue: "2026-04-06", isConstant: true, serializedName: "x-ms-version", type: { name: "String", }, }, }; const requestId = { parameterPath: ["options", "requestId"], mapper: { serializedName: "x-ms-client-request-id", xmlName: "x-ms-client-request-id", type: { name: "String", }, }, }; const accept1 = { parameterPath: "accept", mapper: { defaultValue: "application/xml", isConstant: true, serializedName: "Accept", type: { name: "String", }, }, }; const comp1 = { parameterPath: "comp", mapper: { defaultValue: "stats", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const comp2 = { parameterPath: "comp", mapper: { defaultValue: "list", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const prefix = { parameterPath: ["options", "prefix"], mapper: { serializedName: "prefix", xmlName: "prefix", type: { name: "String", }, }, }; const marker = { parameterPath: ["options", "marker"], mapper: { serializedName: "marker", xmlName: "marker", type: { name: "String", }, }, }; const maxPageSize = { parameterPath: ["options", "maxPageSize"], mapper: { constraints: { InclusiveMinimum: 1, }, serializedName: "maxresults", xmlName: "maxresults", type: { name: "Number", }, }, }; const include = { parameterPath: ["options", "include"], mapper: { serializedName: "include", xmlName: "include", xmlElementName: "ListContainersIncludeType", type: { name: "Sequence", element: { type: { name: "Enum", allowedValues: ["metadata", "deleted", "system"], }, }, }, }, collectionFormat: "CSV", }; const keyInfo = { parameterPath: "keyInfo", mapper: KeyInfo, }; const comp3 = { parameterPath: "comp", mapper: { defaultValue: "userdelegationkey", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const restype1 = { parameterPath: "restype", mapper: { defaultValue: "account", isConstant: true, serializedName: "restype", type: { name: "String", }, }, }; const body = { parameterPath: "body", mapper: { serializedName: "body", required: true, xmlName: "body", type: { name: "Stream", }, }, }; const comp4 = { parameterPath: "comp", mapper: { defaultValue: "batch", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const contentLength = { parameterPath: "contentLength", mapper: { serializedName: "Content-Length", required: true, xmlName: "Content-Length", type: { name: "Number", }, }, }; const multipartContentType = { parameterPath: "multipartContentType", mapper: { serializedName: "Content-Type", required: true, xmlName: "Content-Type", type: { name: "String", }, }, }; const comp5 = { parameterPath: "comp", mapper: { defaultValue: "blobs", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const where = { parameterPath: ["options", "where"], mapper: { serializedName: "where", xmlName: "where", type: { name: "String", }, }, }; const restype2 = { parameterPath: "restype", mapper: { defaultValue: "container", isConstant: true, serializedName: "restype", type: { name: "String", }, }, }; const metadata = { parameterPath: ["options", "metadata"], mapper: { serializedName: "x-ms-meta", xmlName: "x-ms-meta", headerCollectionPrefix: "x-ms-meta-", type: { name: "Dictionary", value: { type: { name: "String" } }, }, }, }; const access = { parameterPath: ["options", "access"], mapper: { serializedName: "x-ms-blob-public-access", xmlName: "x-ms-blob-public-access", type: { name: "Enum", allowedValues: ["container", "blob"], }, }, }; const defaultEncryptionScope = { parameterPath: [ "options", "containerEncryptionScope", "defaultEncryptionScope", ], mapper: { serializedName: "x-ms-default-encryption-scope", xmlName: "x-ms-default-encryption-scope", type: { name: "String", }, }, }; const preventEncryptionScopeOverride = { parameterPath: [ "options", "containerEncryptionScope", "preventEncryptionScopeOverride", ], mapper: { serializedName: "x-ms-deny-encryption-scope-override", xmlName: "x-ms-deny-encryption-scope-override", type: { name: "Boolean", }, }, }; const leaseId = { parameterPath: ["options", "leaseAccessConditions", "leaseId"], mapper: { serializedName: "x-ms-lease-id", xmlName: "x-ms-lease-id", type: { name: "String", }, }, }; const ifModifiedSince = { parameterPath: ["options", "modifiedAccessConditions", "ifModifiedSince"], mapper: { serializedName: "If-Modified-Since", xmlName: "If-Modified-Since", type: { name: "DateTimeRfc1123", }, }, }; const ifUnmodifiedSince = { parameterPath: ["options", "modifiedAccessConditions", "ifUnmodifiedSince"], mapper: { serializedName: "If-Unmodified-Since", xmlName: "If-Unmodified-Since", type: { name: "DateTimeRfc1123", }, }, }; const comp6 = { parameterPath: "comp", mapper: { defaultValue: "metadata", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const comp7 = { parameterPath: "comp", mapper: { defaultValue: "acl", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const containerAcl = { parameterPath: ["options", "containerAcl"], mapper: { serializedName: "containerAcl", xmlName: "SignedIdentifiers", xmlIsWrapped: true, xmlElementName: "SignedIdentifier", type: { name: "Sequence", element: { type: { name: "Composite", className: "SignedIdentifier", }, }, }, }, }; const comp8 = { parameterPath: "comp", mapper: { defaultValue: "undelete", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const deletedContainerName = { parameterPath: ["options", "deletedContainerName"], mapper: { serializedName: "x-ms-deleted-container-name", xmlName: "x-ms-deleted-container-name", type: { name: "String", }, }, }; const deletedContainerVersion = { parameterPath: ["options", "deletedContainerVersion"], mapper: { serializedName: "x-ms-deleted-container-version", xmlName: "x-ms-deleted-container-version", type: { name: "String", }, }, }; const comp9 = { parameterPath: "comp", mapper: { defaultValue: "rename", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const sourceContainerName = { parameterPath: "sourceContainerName", mapper: { serializedName: "x-ms-source-container-name", required: true, xmlName: "x-ms-source-container-name", type: { name: "String", }, }, }; const sourceLeaseId = { parameterPath: ["options", "sourceLeaseId"], mapper: { serializedName: "x-ms-source-lease-id", xmlName: "x-ms-source-lease-id", type: { name: "String", }, }, }; const comp10 = { parameterPath: "comp", mapper: { defaultValue: "lease", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const action = { parameterPath: "action", mapper: { defaultValue: "acquire", isConstant: true, serializedName: "x-ms-lease-action", type: { name: "String", }, }, }; const duration = { parameterPath: ["options", "duration"], mapper: { serializedName: "x-ms-lease-duration", xmlName: "x-ms-lease-duration", type: { name: "Number", }, }, }; const proposedLeaseId = { parameterPath: ["options", "proposedLeaseId"], mapper: { serializedName: "x-ms-proposed-lease-id", xmlName: "x-ms-proposed-lease-id", type: { name: "String", }, }, }; const action1 = { parameterPath: "action", mapper: { defaultValue: "release", isConstant: true, serializedName: "x-ms-lease-action", type: { name: "String", }, }, }; const leaseId1 = { parameterPath: "leaseId", mapper: { serializedName: "x-ms-lease-id", required: true, xmlName: "x-ms-lease-id", type: { name: "String", }, }, }; const action2 = { parameterPath: "action", mapper: { defaultValue: "renew", isConstant: true, serializedName: "x-ms-lease-action", type: { name: "String", }, }, }; const action3 = { parameterPath: "action", mapper: { defaultValue: "break", isConstant: true, serializedName: "x-ms-lease-action", type: { name: "String", }, }, }; const breakPeriod = { parameterPath: ["options", "breakPeriod"], mapper: { serializedName: "x-ms-lease-break-period", xmlName: "x-ms-lease-break-period", type: { name: "Number", }, }, }; const action4 = { parameterPath: "action", mapper: { defaultValue: "change", isConstant: true, serializedName: "x-ms-lease-action", type: { name: "String", }, }, }; const proposedLeaseId1 = { parameterPath: "proposedLeaseId", mapper: { serializedName: "x-ms-proposed-lease-id", required: true, xmlName: "x-ms-proposed-lease-id", type: { name: "String", }, }, }; const include1 = { parameterPath: ["options", "include"], mapper: { serializedName: "include", xmlName: "include", xmlElementName: "ListBlobsIncludeItem", type: { name: "Sequence", element: { type: { name: "Enum", allowedValues: [ "copy", "deleted", "metadata", "snapshots", "uncommittedblobs", "versions", "tags", "immutabilitypolicy", "legalhold", "deletedwithversions", ], }, }, }, }, collectionFormat: "CSV", }; const startFrom = { parameterPath: ["options", "startFrom"], mapper: { serializedName: "startFrom", xmlName: "startFrom", type: { name: "String", }, }, }; const delimiter = { parameterPath: "delimiter", mapper: { serializedName: "delimiter", required: true, xmlName: "delimiter", type: { name: "String", }, }, }; const snapshot = { parameterPath: ["options", "snapshot"], mapper: { serializedName: "snapshot", xmlName: "snapshot", type: { name: "String", }, }, }; const versionId = { parameterPath: ["options", "versionId"], mapper: { serializedName: "versionid", xmlName: "versionid", type: { name: "String", }, }, }; const range = { parameterPath: ["options", "range"], mapper: { serializedName: "x-ms-range", xmlName: "x-ms-range", type: { name: "String", }, }, }; const rangeGetContentMD5 = { parameterPath: ["options", "rangeGetContentMD5"], mapper: { serializedName: "x-ms-range-get-content-md5", xmlName: "x-ms-range-get-content-md5", type: { name: "Boolean", }, }, }; const rangeGetContentCRC64 = { parameterPath: ["options", "rangeGetContentCRC64"], mapper: { serializedName: "x-ms-range-get-content-crc64", xmlName: "x-ms-range-get-content-crc64", type: { name: "Boolean", }, }, }; const structuredBodyType = { parameterPath: ["options", "structuredBodyType"], mapper: { serializedName: "x-ms-structured-body", xmlName: "x-ms-structured-body", type: { name: "String", }, }, }; const encryptionKey = { parameterPath: ["options", "cpkInfo", "encryptionKey"], mapper: { serializedName: "x-ms-encryption-key", xmlName: "x-ms-encryption-key", type: { name: "String", }, }, }; const encryptionKeySha256 = { parameterPath: ["options", "cpkInfo", "encryptionKeySha256"], mapper: { serializedName: "x-ms-encryption-key-sha256", xmlName: "x-ms-encryption-key-sha256", type: { name: "String", }, }, }; const encryptionAlgorithm = { parameterPath: ["options", "cpkInfo", "encryptionAlgorithm"], mapper: { serializedName: "x-ms-encryption-algorithm", xmlName: "x-ms-encryption-algorithm", type: { name: "String", }, }, }; const ifMatch = { parameterPath: ["options", "modifiedAccessConditions", "ifMatch"], mapper: { serializedName: "If-Match", xmlName: "If-Match", type: { name: "String", }, }, }; const ifNoneMatch = { parameterPath: ["options", "modifiedAccessConditions", "ifNoneMatch"], mapper: { serializedName: "If-None-Match", xmlName: "If-None-Match", type: { name: "String", }, }, }; const ifTags = { parameterPath: ["options", "modifiedAccessConditions", "ifTags"], mapper: { serializedName: "x-ms-if-tags", xmlName: "x-ms-if-tags", type: { name: "String", }, }, }; const deleteSnapshots = { parameterPath: ["options", "deleteSnapshots"], mapper: { serializedName: "x-ms-delete-snapshots", xmlName: "x-ms-delete-snapshots", type: { name: "Enum", allowedValues: ["include", "only"], }, }, }; const blobDeleteType = { parameterPath: ["options", "blobDeleteType"], mapper: { serializedName: "deletetype", xmlName: "deletetype", type: { name: "String", }, }, }; const accessTierIfModifiedSince = { parameterPath: ["options", "accessTierIfModifiedSince"], mapper: { serializedName: "x-ms-access-tier-if-modified-since", xmlName: "x-ms-access-tier-if-modified-since", type: { name: "DateTimeRfc1123", }, }, }; const accessTierIfUnmodifiedSince = { parameterPath: ["options", "accessTierIfUnmodifiedSince"], mapper: { serializedName: "x-ms-access-tier-if-unmodified-since", xmlName: "x-ms-access-tier-if-unmodified-since", type: { name: "DateTimeRfc1123", }, }, }; const comp11 = { parameterPath: "comp", mapper: { defaultValue: "expiry", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const expiryOptions = { parameterPath: "expiryOptions", mapper: { serializedName: "x-ms-expiry-option", required: true, xmlName: "x-ms-expiry-option", type: { name: "String", }, }, }; const expiresOn = { parameterPath: ["options", "expiresOn"], mapper: { serializedName: "x-ms-expiry-time", xmlName: "x-ms-expiry-time", type: { name: "String", }, }, }; const blobCacheControl = { parameterPath: ["options", "blobHttpHeaders", "blobCacheControl"], mapper: { serializedName: "x-ms-blob-cache-control", xmlName: "x-ms-blob-cache-control", type: { name: "String", }, }, }; const blobContentType = { parameterPath: ["options", "blobHttpHeaders", "blobContentType"], mapper: { serializedName: "x-ms-blob-content-type", xmlName: "x-ms-blob-content-type", type: { name: "String", }, }, }; const blobContentMD5 = { parameterPath: ["options", "blobHttpHeaders", "blobContentMD5"], mapper: { serializedName: "x-ms-blob-content-md5", xmlName: "x-ms-blob-content-md5", type: { name: "ByteArray", }, }, }; const blobContentEncoding = { parameterPath: ["options", "blobHttpHeaders", "blobContentEncoding"], mapper: { serializedName: "x-ms-blob-content-encoding", xmlName: "x-ms-blob-content-encoding", type: { name: "String", }, }, }; const blobContentLanguage = { parameterPath: ["options", "blobHttpHeaders", "blobContentLanguage"], mapper: { serializedName: "x-ms-blob-content-language", xmlName: "x-ms-blob-content-language", type: { name: "String", }, }, }; const blobContentDisposition = { parameterPath: ["options", "blobHttpHeaders", "blobContentDisposition"], mapper: { serializedName: "x-ms-blob-content-disposition", xmlName: "x-ms-blob-content-disposition", type: { name: "String", }, }, }; const comp12 = { parameterPath: "comp", mapper: { defaultValue: "immutabilityPolicies", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const immutabilityPolicyExpiry = { parameterPath: ["options", "immutabilityPolicyExpiry"], mapper: { serializedName: "x-ms-immutability-policy-until-date", xmlName: "x-ms-immutability-policy-until-date", type: { name: "DateTimeRfc1123", }, }, }; const immutabilityPolicyMode = { parameterPath: ["options", "immutabilityPolicyMode"], mapper: { serializedName: "x-ms-immutability-policy-mode", xmlName: "x-ms-immutability-policy-mode", type: { name: "Enum", allowedValues: ["Mutable", "Unlocked", "Locked"], }, }, }; const comp13 = { parameterPath: "comp", mapper: { defaultValue: "legalhold", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const legalHold = { parameterPath: "legalHold", mapper: { serializedName: "x-ms-legal-hold", required: true, xmlName: "x-ms-legal-hold", type: { name: "Boolean", }, }, }; const encryptionScope = { parameterPath: ["options", "encryptionScope"], mapper: { serializedName: "x-ms-encryption-scope", xmlName: "x-ms-encryption-scope", type: { name: "String", }, }, }; const comp14 = { parameterPath: "comp", mapper: { defaultValue: "snapshot", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const tier = { parameterPath: ["options", "tier"], mapper: { serializedName: "x-ms-access-tier", xmlName: "x-ms-access-tier", type: { name: "Enum", allowedValues: [ "P4", "P6", "P10", "P15", "P20", "P30", "P40", "P50", "P60", "P70", "P80", "Hot", "Cool", "Archive", "Cold", ], }, }, }; const rehydratePriority = { parameterPath: ["options", "rehydratePriority"], mapper: { serializedName: "x-ms-rehydrate-priority", xmlName: "x-ms-rehydrate-priority", type: { name: "Enum", allowedValues: ["High", "Standard"], }, }, }; const sourceIfModifiedSince = { parameterPath: [ "options", "sourceModifiedAccessConditions", "sourceIfModifiedSince", ], mapper: { serializedName: "x-ms-source-if-modified-since", xmlName: "x-ms-source-if-modified-since", type: { name: "DateTimeRfc1123", }, }, }; const sourceIfUnmodifiedSince = { parameterPath: [ "options", "sourceModifiedAccessConditions", "sourceIfUnmodifiedSince", ], mapper: { serializedName: "x-ms-source-if-unmodified-since", xmlName: "x-ms-source-if-unmodified-since", type: { name: "DateTimeRfc1123", }, }, }; const sourceIfMatch = { parameterPath: ["options", "sourceModifiedAccessConditions", "sourceIfMatch"], mapper: { serializedName: "x-ms-source-if-match", xmlName: "x-ms-source-if-match", type: { name: "String", }, }, }; const sourceIfNoneMatch = { parameterPath: [ "options", "sourceModifiedAccessConditions", "sourceIfNoneMatch", ], mapper: { serializedName: "x-ms-source-if-none-match", xmlName: "x-ms-source-if-none-match", type: { name: "String", }, }, }; const sourceIfTags = { parameterPath: ["options", "sourceModifiedAccessConditions", "sourceIfTags"], mapper: { serializedName: "x-ms-source-if-tags", xmlName: "x-ms-source-if-tags", type: { name: "String", }, }, }; const copySource = { parameterPath: "copySource", mapper: { serializedName: "x-ms-copy-source", required: true, xmlName: "x-ms-copy-source", type: { name: "String", }, }, }; const blobTagsString = { parameterPath: ["options", "blobTagsString"], mapper: { serializedName: "x-ms-tags", xmlName: "x-ms-tags", type: { name: "String", }, }, }; const sealBlob = { parameterPath: ["options", "sealBlob"], mapper: { serializedName: "x-ms-seal-blob", xmlName: "x-ms-seal-blob", type: { name: "Boolean", }, }, }; const legalHold1 = { parameterPath: ["options", "legalHold"], mapper: { serializedName: "x-ms-legal-hold", xmlName: "x-ms-legal-hold", type: { name: "Boolean", }, }, }; const xMsRequiresSync = { parameterPath: "xMsRequiresSync", mapper: { defaultValue: "true", isConstant: true, serializedName: "x-ms-requires-sync", type: { name: "String", }, }, }; const sourceContentMD5 = { parameterPath: ["options", "sourceContentMD5"], mapper: { serializedName: "x-ms-source-content-md5", xmlName: "x-ms-source-content-md5", type: { name: "ByteArray", }, }, }; const copySourceAuthorization = { parameterPath: ["options", "copySourceAuthorization"], mapper: { serializedName: "x-ms-copy-source-authorization", xmlName: "x-ms-copy-source-authorization", type: { name: "String", }, }, }; const copySourceTags = { parameterPath: ["options", "copySourceTags"], mapper: { serializedName: "x-ms-copy-source-tag-option", xmlName: "x-ms-copy-source-tag-option", type: { name: "Enum", allowedValues: ["REPLACE", "COPY"], }, }, }; const fileRequestIntent = { parameterPath: ["options", "fileRequestIntent"], mapper: { serializedName: "x-ms-file-request-intent", xmlName: "x-ms-file-request-intent", type: { name: "String", }, }, }; const comp15 = { parameterPath: "comp", mapper: { defaultValue: "copy", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const copyActionAbortConstant = { parameterPath: "copyActionAbortConstant", mapper: { defaultValue: "abort", isConstant: true, serializedName: "x-ms-copy-action", type: { name: "String", }, }, }; const copyId = { parameterPath: "copyId", mapper: { serializedName: "copyid", required: true, xmlName: "copyid", type: { name: "String", }, }, }; const comp16 = { parameterPath: "comp", mapper: { defaultValue: "tier", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const tier1 = { parameterPath: "tier", mapper: { serializedName: "x-ms-access-tier", required: true, xmlName: "x-ms-access-tier", type: { name: "Enum", allowedValues: [ "P4", "P6", "P10", "P15", "P20", "P30", "P40", "P50", "P60", "P70", "P80", "Hot", "Cool", "Archive", "Cold", ], }, }, }; const queryRequest = { parameterPath: ["options", "queryRequest"], mapper: QueryRequest, }; const comp17 = { parameterPath: "comp", mapper: { defaultValue: "query", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const comp18 = { parameterPath: "comp", mapper: { defaultValue: "tags", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const ifModifiedSince1 = { parameterPath: ["options", "blobModifiedAccessConditions", "ifModifiedSince"], mapper: { serializedName: "x-ms-blob-if-modified-since", xmlName: "x-ms-blob-if-modified-since", type: { name: "DateTimeRfc1123", }, }, }; const ifUnmodifiedSince1 = { parameterPath: [ "options", "blobModifiedAccessConditions", "ifUnmodifiedSince", ], mapper: { serializedName: "x-ms-blob-if-unmodified-since", xmlName: "x-ms-blob-if-unmodified-since", type: { name: "DateTimeRfc1123", }, }, }; const ifMatch1 = { parameterPath: ["options", "blobModifiedAccessConditions", "ifMatch"], mapper: { serializedName: "x-ms-blob-if-match", xmlName: "x-ms-blob-if-match", type: { name: "String", }, }, }; const ifNoneMatch1 = { parameterPath: ["options", "blobModifiedAccessConditions", "ifNoneMatch"], mapper: { serializedName: "x-ms-blob-if-none-match", xmlName: "x-ms-blob-if-none-match", type: { name: "String", }, }, }; const tags = { parameterPath: ["options", "tags"], mapper: BlobTags, }; const transactionalContentMD5 = { parameterPath: ["options", "transactionalContentMD5"], mapper: { serializedName: "Content-MD5", xmlName: "Content-MD5", type: { name: "ByteArray", }, }, }; const transactionalContentCrc64 = { parameterPath: ["options", "transactionalContentCrc64"], mapper: { serializedName: "x-ms-content-crc64", xmlName: "x-ms-content-crc64", type: { name: "ByteArray", }, }, }; const blobType = { parameterPath: "blobType", mapper: { defaultValue: "PageBlob", isConstant: true, serializedName: "x-ms-blob-type", type: { name: "String", }, }, }; const blobContentLength = { parameterPath: "blobContentLength", mapper: { serializedName: "x-ms-blob-content-length", required: true, xmlName: "x-ms-blob-content-length", type: { name: "Number", }, }, }; const blobSequenceNumber = { parameterPath: ["options", "blobSequenceNumber"], mapper: { defaultValue: 0, serializedName: "x-ms-blob-sequence-number", xmlName: "x-ms-blob-sequence-number", type: { name: "Number", }, }, }; const contentType1 = { parameterPath: ["options", "contentType"], mapper: { defaultValue: "application/octet-stream", isConstant: true, serializedName: "Content-Type", type: { name: "String", }, }, }; const body1 = { parameterPath: "body", mapper: { serializedName: "body", required: true, xmlName: "body", type: { name: "Stream", }, }, }; const accept2 = { parameterPath: "accept", mapper: { defaultValue: "application/xml", isConstant: true, serializedName: "Accept", type: { name: "String", }, }, }; const comp19 = { parameterPath: "comp", mapper: { defaultValue: "page", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const pageWrite = { parameterPath: "pageWrite", mapper: { defaultValue: "update", isConstant: true, serializedName: "x-ms-page-write", type: { name: "String", }, }, }; const ifSequenceNumberLessThanOrEqualTo = { parameterPath: [ "options", "sequenceNumberAccessConditions", "ifSequenceNumberLessThanOrEqualTo", ], mapper: { serializedName: "x-ms-if-sequence-number-le", xmlName: "x-ms-if-sequence-number-le", type: { name: "Number", }, }, }; const ifSequenceNumberLessThan = { parameterPath: [ "options", "sequenceNumberAccessConditions", "ifSequenceNumberLessThan", ], mapper: { serializedName: "x-ms-if-sequence-number-lt", xmlName: "x-ms-if-sequence-number-lt", type: { name: "Number", }, }, }; const ifSequenceNumberEqualTo = { parameterPath: [ "options", "sequenceNumberAccessConditions", "ifSequenceNumberEqualTo", ], mapper: { serializedName: "x-ms-if-sequence-number-eq", xmlName: "x-ms-if-sequence-number-eq", type: { name: "Number", }, }, }; const structuredContentLength = { parameterPath: ["options", "structuredContentLength"], mapper: { serializedName: "x-ms-structured-content-length", xmlName: "x-ms-structured-content-length", type: { name: "Number", }, }, }; const pageWrite1 = { parameterPath: "pageWrite", mapper: { defaultValue: "clear", isConstant: true, serializedName: "x-ms-page-write", type: { name: "String", }, }, }; const sourceUrl = { parameterPath: "sourceUrl", mapper: { serializedName: "x-ms-copy-source", required: true, xmlName: "x-ms-copy-source", type: { name: "String", }, }, }; const sourceRange = { parameterPath: "sourceRange", mapper: { serializedName: "x-ms-source-range", required: true, xmlName: "x-ms-source-range", type: { name: "String", }, }, }; const sourceContentCrc64 = { parameterPath: ["options", "sourceContentCrc64"], mapper: { serializedName: "x-ms-source-content-crc64", xmlName: "x-ms-source-content-crc64", type: { name: "ByteArray", }, }, }; const range1 = { parameterPath: "range", mapper: { serializedName: "x-ms-range", required: true, xmlName: "x-ms-range", type: { name: "String", }, }, }; const sourceEncryptionKey = { parameterPath: ["options", "sourceCpkInfo", "sourceEncryptionKey"], mapper: { serializedName: "x-ms-source-encryption-key", xmlName: "x-ms-source-encryption-key", type: { name: "String", }, }, }; const sourceEncryptionKeySha256 = { parameterPath: ["options", "sourceCpkInfo", "sourceEncryptionKeySha256"], mapper: { serializedName: "x-ms-source-encryption-key-sha256", xmlName: "x-ms-source-encryption-key-sha256", type: { name: "String", }, }, }; const sourceEncryptionAlgorithm = { parameterPath: ["options", "sourceCpkInfo", "sourceEncryptionAlgorithm"], mapper: { serializedName: "x-ms-source-encryption-algorithm", xmlName: "x-ms-source-encryption-algorithm", type: { name: "String", }, }, }; const comp20 = { parameterPath: "comp", mapper: { defaultValue: "pagelist", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const prevsnapshot = { parameterPath: ["options", "prevsnapshot"], mapper: { serializedName: "prevsnapshot", xmlName: "prevsnapshot", type: { name: "String", }, }, }; const prevSnapshotUrl = { parameterPath: ["options", "prevSnapshotUrl"], mapper: { serializedName: "x-ms-previous-snapshot-url", xmlName: "x-ms-previous-snapshot-url", type: { name: "String", }, }, }; const sequenceNumberAction = { parameterPath: "sequenceNumberAction", mapper: { serializedName: "x-ms-sequence-number-action", required: true, xmlName: "x-ms-sequence-number-action", type: { name: "Enum", allowedValues: ["max", "update", "increment"], }, }, }; const comp21 = { parameterPath: "comp", mapper: { defaultValue: "incrementalcopy", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const blobType1 = { parameterPath: "blobType", mapper: { defaultValue: "AppendBlob", isConstant: true, serializedName: "x-ms-blob-type", type: { name: "String", }, }, }; const comp22 = { parameterPath: "comp", mapper: { defaultValue: "appendblock", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const maxSize = { parameterPath: ["options", "appendPositionAccessConditions", "maxSize"], mapper: { serializedName: "x-ms-blob-condition-maxsize", xmlName: "x-ms-blob-condition-maxsize", type: { name: "Number", }, }, }; const appendPosition = { parameterPath: [ "options", "appendPositionAccessConditions", "appendPosition", ], mapper: { serializedName: "x-ms-blob-condition-appendpos", xmlName: "x-ms-blob-condition-appendpos", type: { name: "Number", }, }, }; const sourceRange1 = { parameterPath: ["options", "sourceRange"], mapper: { serializedName: "x-ms-source-range", xmlName: "x-ms-source-range", type: { name: "String", }, }, }; const comp23 = { parameterPath: "comp", mapper: { defaultValue: "seal", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const blobType2 = { parameterPath: "blobType", mapper: { defaultValue: "BlockBlob", isConstant: true, serializedName: "x-ms-blob-type", type: { name: "String", }, }, }; const copySourceBlobProperties = { parameterPath: ["options", "copySourceBlobProperties"], mapper: { serializedName: "x-ms-copy-source-blob-properties", xmlName: "x-ms-copy-source-blob-properties", type: { name: "Boolean", }, }, }; const comp24 = { parameterPath: "comp", mapper: { defaultValue: "block", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const blockId = { parameterPath: "blockId", mapper: { serializedName: "blockid", required: true, xmlName: "blockid", type: { name: "String", }, }, }; const blocks = { parameterPath: "blocks", mapper: BlockLookupList, }; const comp25 = { parameterPath: "comp", mapper: { defaultValue: "blocklist", isConstant: true, serializedName: "comp", type: { name: "String", }, }, }; const listType = { parameterPath: "listType", mapper: { defaultValue: "committed", serializedName: "blocklisttype", required: true, xmlName: "blocklisttype", type: { name: "Enum", allowedValues: ["committed", "uncommitted", "all"], }, }, }; /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ /** Class containing Service operations. */ class ServiceImpl { client; /** * Initialize a new instance of the class Service class. * @param client Reference to the service client */ constructor(client) { this.client = client; } /** * Sets properties for a storage account's Blob service endpoint, including properties for Storage * Analytics and CORS (Cross-Origin Resource Sharing) rules * @param blobServiceProperties The StorageService properties. * @param options The options parameters. */ setProperties(blobServiceProperties, options) { return this.client.sendOperationRequest({ blobServiceProperties, options }, setPropertiesOperationSpec); } /** * gets the properties of a storage account's Blob service, including properties for Storage Analytics * and CORS (Cross-Origin Resource Sharing) rules. * @param options The options parameters. */ getProperties(options) { return this.client.sendOperationRequest({ options }, getPropertiesOperationSpec$2); } /** * Retrieves statistics related to replication for the Blob service. It is only available on the * secondary location endpoint when read-access geo-redundant replication is enabled for the storage * account. * @param options The options parameters. */ getStatistics(options) { return this.client.sendOperationRequest({ options }, getStatisticsOperationSpec); } /** * The List Containers Segment operation returns a list of the containers under the specified account * @param options The options parameters. */ listContainersSegment(options) { return this.client.sendOperationRequest({ options }, listContainersSegmentOperationSpec); } /** * Retrieves a user delegation key for the Blob service. This is only a valid operation when using * bearer token authentication. * @param keyInfo Key information * @param options The options parameters. */ getUserDelegationKey(keyInfo, options) { return this.client.sendOperationRequest({ keyInfo, options }, getUserDelegationKeyOperationSpec); } /** * Returns the sku name and account kind * @param options The options parameters. */ getAccountInfo(options) { return this.client.sendOperationRequest({ options }, getAccountInfoOperationSpec$2); } /** * The Batch operation allows multiple API calls to be embedded into a single HTTP request. * @param contentLength The length of the request. * @param multipartContentType Required. The value of this header must be multipart/mixed with a batch * boundary. Example header value: multipart/mixed; boundary=batch_ * @param body Initial data * @param options The options parameters. */ submitBatch(contentLength, multipartContentType, body, options) { return this.client.sendOperationRequest({ contentLength, multipartContentType, body, options }, submitBatchOperationSpec$1); } /** * The Filter Blobs operation enables callers to list blobs across all containers whose tags match a * given search expression. Filter blobs searches across all containers within a storage account but * can be scoped within the expression to a single container. * @param options The options parameters. */ filterBlobs(options) { return this.client.sendOperationRequest({ options }, filterBlobsOperationSpec$1); } } // Operation Specifications const xmlSerializer$5 = createSerializer(Mappers, /* isXml */ true); const setPropertiesOperationSpec = { path: "/", httpMethod: "PUT", responses: { 202: { headersMapper: ServiceSetPropertiesHeaders, }, default: { bodyMapper: StorageError, headersMapper: ServiceSetPropertiesExceptionHeaders, }, }, requestBody: blobServiceProperties, queryParameters: [ restype, comp, timeoutInSeconds, ], urlParameters: [url], headerParameters: [ contentType, accept, version$1, requestId, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "xml", serializer: xmlSerializer$5, }; const getPropertiesOperationSpec$2 = { path: "/", httpMethod: "GET", responses: { 200: { bodyMapper: BlobServiceProperties, headersMapper: ServiceGetPropertiesHeaders, }, default: { bodyMapper: StorageError, headersMapper: ServiceGetPropertiesExceptionHeaders, }, }, queryParameters: [ restype, comp, timeoutInSeconds, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$5, }; const getStatisticsOperationSpec = { path: "/", httpMethod: "GET", responses: { 200: { bodyMapper: BlobServiceStatistics, headersMapper: ServiceGetStatisticsHeaders, }, default: { bodyMapper: StorageError, headersMapper: ServiceGetStatisticsExceptionHeaders, }, }, queryParameters: [ restype, timeoutInSeconds, comp1, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$5, }; const listContainersSegmentOperationSpec = { path: "/", httpMethod: "GET", responses: { 200: { bodyMapper: ListContainersSegmentResponse, headersMapper: ServiceListContainersSegmentHeaders, }, default: { bodyMapper: StorageError, headersMapper: ServiceListContainersSegmentExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, comp2, prefix, marker, maxPageSize, include, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$5, }; const getUserDelegationKeyOperationSpec = { path: "/", httpMethod: "POST", responses: { 200: { bodyMapper: UserDelegationKey, headersMapper: ServiceGetUserDelegationKeyHeaders, }, default: { bodyMapper: StorageError, headersMapper: ServiceGetUserDelegationKeyExceptionHeaders, }, }, requestBody: keyInfo, queryParameters: [ restype, timeoutInSeconds, comp3, ], urlParameters: [url], headerParameters: [ contentType, accept, version$1, requestId, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "xml", serializer: xmlSerializer$5, }; const getAccountInfoOperationSpec$2 = { path: "/", httpMethod: "GET", responses: { 200: { headersMapper: ServiceGetAccountInfoHeaders, }, default: { bodyMapper: StorageError, headersMapper: ServiceGetAccountInfoExceptionHeaders, }, }, queryParameters: [ comp, timeoutInSeconds, restype1, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$5, }; const submitBatchOperationSpec$1 = { path: "/", httpMethod: "POST", responses: { 202: { bodyMapper: { type: { name: "Stream" }, serializedName: "parsedResponse", }, headersMapper: ServiceSubmitBatchHeaders, }, default: { bodyMapper: StorageError, headersMapper: ServiceSubmitBatchExceptionHeaders, }, }, requestBody: body, queryParameters: [timeoutInSeconds, comp4], urlParameters: [url], headerParameters: [ accept, version$1, requestId, contentLength, multipartContentType, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "xml", serializer: xmlSerializer$5, }; const filterBlobsOperationSpec$1 = { path: "/", httpMethod: "GET", responses: { 200: { bodyMapper: FilterBlobSegment, headersMapper: ServiceFilterBlobsHeaders, }, default: { bodyMapper: StorageError, headersMapper: ServiceFilterBlobsExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, marker, maxPageSize, comp5, where, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$5, }; /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ /** Class containing Container operations. */ class ContainerImpl { client; /** * Initialize a new instance of the class Container class. * @param client Reference to the service client */ constructor(client) { this.client = client; } /** * creates a new container under the specified account. If the container with the same name already * exists, the operation fails * @param options The options parameters. */ create(options) { return this.client.sendOperationRequest({ options }, createOperationSpec$2); } /** * returns all user-defined metadata and system properties for the specified container. The data * returned does not include the container's list of blobs * @param options The options parameters. */ getProperties(options) { return this.client.sendOperationRequest({ options }, getPropertiesOperationSpec$1); } /** * operation marks the specified container for deletion. The container and any blobs contained within * it are later deleted during garbage collection * @param options The options parameters. */ delete(options) { return this.client.sendOperationRequest({ options }, deleteOperationSpec$1); } /** * operation sets one or more user-defined name-value pairs for the specified container. * @param options The options parameters. */ setMetadata(options) { return this.client.sendOperationRequest({ options }, setMetadataOperationSpec$1); } /** * gets the permissions for the specified container. The permissions indicate whether container data * may be accessed publicly. * @param options The options parameters. */ getAccessPolicy(options) { return this.client.sendOperationRequest({ options }, getAccessPolicyOperationSpec); } /** * sets the permissions for the specified container. The permissions indicate whether blobs in a * container may be accessed publicly. * @param options The options parameters. */ setAccessPolicy(options) { return this.client.sendOperationRequest({ options }, setAccessPolicyOperationSpec); } /** * Restores a previously-deleted container. * @param options The options parameters. */ restore(options) { return this.client.sendOperationRequest({ options }, restoreOperationSpec); } /** * Renames an existing container. * @param sourceContainerName Required. Specifies the name of the container to rename. * @param options The options parameters. */ rename(sourceContainerName, options) { return this.client.sendOperationRequest({ sourceContainerName, options }, renameOperationSpec); } /** * The Batch operation allows multiple API calls to be embedded into a single HTTP request. * @param contentLength The length of the request. * @param multipartContentType Required. The value of this header must be multipart/mixed with a batch * boundary. Example header value: multipart/mixed; boundary=batch_ * @param body Initial data * @param options The options parameters. */ submitBatch(contentLength, multipartContentType, body, options) { return this.client.sendOperationRequest({ contentLength, multipartContentType, body, options }, submitBatchOperationSpec); } /** * The Filter Blobs operation enables callers to list blobs in a container whose tags match a given * search expression. Filter blobs searches within the given container. * @param options The options parameters. */ filterBlobs(options) { return this.client.sendOperationRequest({ options }, filterBlobsOperationSpec); } /** * [Update] establishes and manages a lock on a container for delete operations. The lock duration can * be 15 to 60 seconds, or can be infinite * @param options The options parameters. */ acquireLease(options) { return this.client.sendOperationRequest({ options }, acquireLeaseOperationSpec$1); } /** * [Update] establishes and manages a lock on a container for delete operations. The lock duration can * be 15 to 60 seconds, or can be infinite * @param leaseId Specifies the current lease ID on the resource. * @param options The options parameters. */ releaseLease(leaseId, options) { return this.client.sendOperationRequest({ leaseId, options }, releaseLeaseOperationSpec$1); } /** * [Update] establishes and manages a lock on a container for delete operations. The lock duration can * be 15 to 60 seconds, or can be infinite * @param leaseId Specifies the current lease ID on the resource. * @param options The options parameters. */ renewLease(leaseId, options) { return this.client.sendOperationRequest({ leaseId, options }, renewLeaseOperationSpec$1); } /** * [Update] establishes and manages a lock on a container for delete operations. The lock duration can * be 15 to 60 seconds, or can be infinite * @param options The options parameters. */ breakLease(options) { return this.client.sendOperationRequest({ options }, breakLeaseOperationSpec$1); } /** * [Update] establishes and manages a lock on a container for delete operations. The lock duration can * be 15 to 60 seconds, or can be infinite * @param leaseId Specifies the current lease ID on the resource. * @param proposedLeaseId Proposed lease ID, in a GUID string format. The Blob service returns 400 * (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor * (String) for a list of valid GUID string formats. * @param options The options parameters. */ changeLease(leaseId, proposedLeaseId, options) { return this.client.sendOperationRequest({ leaseId, proposedLeaseId, options }, changeLeaseOperationSpec$1); } /** * [Update] The List Blobs operation returns a list of the blobs under the specified container * @param options The options parameters. */ listBlobFlatSegment(options) { return this.client.sendOperationRequest({ options }, listBlobFlatSegmentOperationSpec); } /** * [Update] The List Blobs operation returns a list of the blobs under the specified container * @param delimiter When the request includes this parameter, the operation returns a BlobPrefix * element in the response body that acts as a placeholder for all blobs whose names begin with the * same substring up to the appearance of the delimiter character. The delimiter may be a single * character or a string. * @param options The options parameters. */ listBlobHierarchySegment(delimiter, options) { return this.client.sendOperationRequest({ delimiter, options }, listBlobHierarchySegmentOperationSpec); } /** * Returns the sku name and account kind * @param options The options parameters. */ getAccountInfo(options) { return this.client.sendOperationRequest({ options }, getAccountInfoOperationSpec$1); } } // Operation Specifications const xmlSerializer$4 = createSerializer(Mappers, /* isXml */ true); const createOperationSpec$2 = { path: "/{containerName}", httpMethod: "PUT", responses: { 201: { headersMapper: ContainerCreateHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerCreateExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, restype2], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, metadata, access, defaultEncryptionScope, preventEncryptionScopeOverride, ], isXML: true, serializer: xmlSerializer$4, }; const getPropertiesOperationSpec$1 = { path: "/{containerName}", httpMethod: "GET", responses: { 200: { headersMapper: ContainerGetPropertiesHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerGetPropertiesExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, restype2], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ], isXML: true, serializer: xmlSerializer$4, }; const deleteOperationSpec$1 = { path: "/{containerName}", httpMethod: "DELETE", responses: { 202: { headersMapper: ContainerDeleteHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerDeleteExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, restype2], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, ], isXML: true, serializer: xmlSerializer$4, }; const setMetadataOperationSpec$1 = { path: "/{containerName}", httpMethod: "PUT", responses: { 200: { headersMapper: ContainerSetMetadataHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerSetMetadataExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, restype2, comp6, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, metadata, leaseId, ifModifiedSince, ], isXML: true, serializer: xmlSerializer$4, }; const getAccessPolicyOperationSpec = { path: "/{containerName}", httpMethod: "GET", responses: { 200: { bodyMapper: { type: { name: "Sequence", element: { type: { name: "Composite", className: "SignedIdentifier" }, }, }, serializedName: "SignedIdentifiers", xmlName: "SignedIdentifiers", xmlIsWrapped: true, xmlElementName: "SignedIdentifier", }, headersMapper: ContainerGetAccessPolicyHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerGetAccessPolicyExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, restype2, comp7, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ], isXML: true, serializer: xmlSerializer$4, }; const setAccessPolicyOperationSpec = { path: "/{containerName}", httpMethod: "PUT", responses: { 200: { headersMapper: ContainerSetAccessPolicyHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerSetAccessPolicyExceptionHeaders, }, }, requestBody: containerAcl, queryParameters: [ timeoutInSeconds, restype2, comp7, ], urlParameters: [url], headerParameters: [ contentType, accept, version$1, requestId, access, leaseId, ifModifiedSince, ifUnmodifiedSince, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "xml", serializer: xmlSerializer$4, }; const restoreOperationSpec = { path: "/{containerName}", httpMethod: "PUT", responses: { 201: { headersMapper: ContainerRestoreHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerRestoreExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, restype2, comp8, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, deletedContainerName, deletedContainerVersion, ], isXML: true, serializer: xmlSerializer$4, }; const renameOperationSpec = { path: "/{containerName}", httpMethod: "PUT", responses: { 200: { headersMapper: ContainerRenameHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerRenameExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, restype2, comp9, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, sourceContainerName, sourceLeaseId, ], isXML: true, serializer: xmlSerializer$4, }; const submitBatchOperationSpec = { path: "/{containerName}", httpMethod: "POST", responses: { 202: { bodyMapper: { type: { name: "Stream" }, serializedName: "parsedResponse", }, headersMapper: ContainerSubmitBatchHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerSubmitBatchExceptionHeaders, }, }, requestBody: body, queryParameters: [ timeoutInSeconds, comp4, restype2, ], urlParameters: [url], headerParameters: [ accept, version$1, requestId, contentLength, multipartContentType, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "xml", serializer: xmlSerializer$4, }; const filterBlobsOperationSpec = { path: "/{containerName}", httpMethod: "GET", responses: { 200: { bodyMapper: FilterBlobSegment, headersMapper: ContainerFilterBlobsHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerFilterBlobsExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, marker, maxPageSize, comp5, where, restype2, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$4, }; const acquireLeaseOperationSpec$1 = { path: "/{containerName}", httpMethod: "PUT", responses: { 201: { headersMapper: ContainerAcquireLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerAcquireLeaseExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, restype2, comp10, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, action, duration, proposedLeaseId, ], isXML: true, serializer: xmlSerializer$4, }; const releaseLeaseOperationSpec$1 = { path: "/{containerName}", httpMethod: "PUT", responses: { 200: { headersMapper: ContainerReleaseLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerReleaseLeaseExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, restype2, comp10, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, action1, leaseId1, ], isXML: true, serializer: xmlSerializer$4, }; const renewLeaseOperationSpec$1 = { path: "/{containerName}", httpMethod: "PUT", responses: { 200: { headersMapper: ContainerRenewLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerRenewLeaseExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, restype2, comp10, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, leaseId1, action2, ], isXML: true, serializer: xmlSerializer$4, }; const breakLeaseOperationSpec$1 = { path: "/{containerName}", httpMethod: "PUT", responses: { 202: { headersMapper: ContainerBreakLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerBreakLeaseExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, restype2, comp10, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, action3, breakPeriod, ], isXML: true, serializer: xmlSerializer$4, }; const changeLeaseOperationSpec$1 = { path: "/{containerName}", httpMethod: "PUT", responses: { 200: { headersMapper: ContainerChangeLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerChangeLeaseExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, restype2, comp10, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, leaseId1, action4, proposedLeaseId1, ], isXML: true, serializer: xmlSerializer$4, }; const listBlobFlatSegmentOperationSpec = { path: "/{containerName}", httpMethod: "GET", responses: { 200: { bodyMapper: ListBlobsFlatSegmentResponse, headersMapper: ContainerListBlobFlatSegmentHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerListBlobFlatSegmentExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, comp2, prefix, marker, maxPageSize, restype2, include1, startFrom, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$4, }; const listBlobHierarchySegmentOperationSpec = { path: "/{containerName}", httpMethod: "GET", responses: { 200: { bodyMapper: ListBlobsHierarchySegmentResponse, headersMapper: ContainerListBlobHierarchySegmentHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerListBlobHierarchySegmentExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, comp2, prefix, marker, maxPageSize, restype2, include1, startFrom, delimiter, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$4, }; const getAccountInfoOperationSpec$1 = { path: "/{containerName}", httpMethod: "GET", responses: { 200: { headersMapper: ContainerGetAccountInfoHeaders, }, default: { bodyMapper: StorageError, headersMapper: ContainerGetAccountInfoExceptionHeaders, }, }, queryParameters: [ comp, timeoutInSeconds, restype1, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$4, }; /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ /** Class containing Blob operations. */ class BlobImpl { client; /** * Initialize a new instance of the class Blob class. * @param client Reference to the service client */ constructor(client) { this.client = client; } /** * The Download operation reads or downloads a blob from the system, including its metadata and * properties. You can also call Download to read a snapshot. * @param options The options parameters. */ download(options) { return this.client.sendOperationRequest({ options }, downloadOperationSpec); } /** * The Get Properties operation returns all user-defined metadata, standard HTTP properties, and system * properties for the blob. It does not return the content of the blob. * @param options The options parameters. */ getProperties(options) { return this.client.sendOperationRequest({ options }, getPropertiesOperationSpec); } /** * If the storage account's soft delete feature is disabled then, when a blob is deleted, it is * permanently removed from the storage account. If the storage account's soft delete feature is * enabled, then, when a blob is deleted, it is marked for deletion and becomes inaccessible * immediately. However, the blob service retains the blob or snapshot for the number of days specified * by the DeleteRetentionPolicy section of [Storage service properties] * (Set-Blob-Service-Properties.md). After the specified number of days has passed, the blob's data is * permanently removed from the storage account. Note that you continue to be charged for the * soft-deleted blob's storage until it is permanently removed. Use the List Blobs API and specify the * "include=deleted" query parameter to discover which blobs and snapshots have been soft deleted. You * can then use the Undelete Blob API to restore a soft-deleted blob. All other operations on a * soft-deleted blob or snapshot causes the service to return an HTTP status code of 404 * (ResourceNotFound). * @param options The options parameters. */ delete(options) { return this.client.sendOperationRequest({ options }, deleteOperationSpec); } /** * Undelete a blob that was previously soft deleted * @param options The options parameters. */ undelete(options) { return this.client.sendOperationRequest({ options }, undeleteOperationSpec); } /** * Sets the time a blob will expire and be deleted. * @param expiryOptions Required. Indicates mode of the expiry time * @param options The options parameters. */ setExpiry(expiryOptions, options) { return this.client.sendOperationRequest({ expiryOptions, options }, setExpiryOperationSpec); } /** * The Set HTTP Headers operation sets system properties on the blob * @param options The options parameters. */ setHttpHeaders(options) { return this.client.sendOperationRequest({ options }, setHttpHeadersOperationSpec); } /** * The Set Immutability Policy operation sets the immutability policy on the blob * @param options The options parameters. */ setImmutabilityPolicy(options) { return this.client.sendOperationRequest({ options }, setImmutabilityPolicyOperationSpec); } /** * The Delete Immutability Policy operation deletes the immutability policy on the blob * @param options The options parameters. */ deleteImmutabilityPolicy(options) { return this.client.sendOperationRequest({ options }, deleteImmutabilityPolicyOperationSpec); } /** * The Set Legal Hold operation sets a legal hold on the blob. * @param legalHold Specified if a legal hold should be set on the blob. * @param options The options parameters. */ setLegalHold(legalHold, options) { return this.client.sendOperationRequest({ legalHold, options }, setLegalHoldOperationSpec); } /** * The Set Blob Metadata operation sets user-defined metadata for the specified blob as one or more * name-value pairs * @param options The options parameters. */ setMetadata(options) { return this.client.sendOperationRequest({ options }, setMetadataOperationSpec); } /** * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete * operations * @param options The options parameters. */ acquireLease(options) { return this.client.sendOperationRequest({ options }, acquireLeaseOperationSpec); } /** * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete * operations * @param leaseId Specifies the current lease ID on the resource. * @param options The options parameters. */ releaseLease(leaseId, options) { return this.client.sendOperationRequest({ leaseId, options }, releaseLeaseOperationSpec); } /** * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete * operations * @param leaseId Specifies the current lease ID on the resource. * @param options The options parameters. */ renewLease(leaseId, options) { return this.client.sendOperationRequest({ leaseId, options }, renewLeaseOperationSpec); } /** * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete * operations * @param leaseId Specifies the current lease ID on the resource. * @param proposedLeaseId Proposed lease ID, in a GUID string format. The Blob service returns 400 * (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor * (String) for a list of valid GUID string formats. * @param options The options parameters. */ changeLease(leaseId, proposedLeaseId, options) { return this.client.sendOperationRequest({ leaseId, proposedLeaseId, options }, changeLeaseOperationSpec); } /** * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete * operations * @param options The options parameters. */ breakLease(options) { return this.client.sendOperationRequest({ options }, breakLeaseOperationSpec); } /** * The Create Snapshot operation creates a read-only snapshot of a blob * @param options The options parameters. */ createSnapshot(options) { return this.client.sendOperationRequest({ options }, createSnapshotOperationSpec); } /** * The Start Copy From URL operation copies a blob or an internet resource to a new blob. * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to * 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would * appear in a request URI. The source blob must either be public or must be authenticated via a shared * access signature. * @param options The options parameters. */ startCopyFromURL(copySource, options) { return this.client.sendOperationRequest({ copySource, options }, startCopyFromURLOperationSpec); } /** * The Copy From URL operation copies a blob or an internet resource to a new blob. It will not return * a response until the copy is complete. * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to * 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would * appear in a request URI. The source blob must either be public or must be authenticated via a shared * access signature. * @param options The options parameters. */ copyFromURL(copySource, options) { return this.client.sendOperationRequest({ copySource, options }, copyFromURLOperationSpec); } /** * The Abort Copy From URL operation aborts a pending Copy From URL operation, and leaves a destination * blob with zero length and full metadata. * @param copyId The copy identifier provided in the x-ms-copy-id header of the original Copy Blob * operation. * @param options The options parameters. */ abortCopyFromURL(copyId, options) { return this.client.sendOperationRequest({ copyId, options }, abortCopyFromURLOperationSpec); } /** * The Set Tier operation sets the tier on a blob. The operation is allowed on a page blob in a premium * storage account and on a block blob in a blob storage account (locally redundant storage only). A * premium page blob's tier determines the allowed size, IOPS, and bandwidth of the blob. A block * blob's tier determines Hot/Cool/Archive storage type. This operation does not update the blob's * ETag. * @param tier Indicates the tier to be set on the blob. * @param options The options parameters. */ setTier(tier, options) { return this.client.sendOperationRequest({ tier, options }, setTierOperationSpec); } /** * Returns the sku name and account kind * @param options The options parameters. */ getAccountInfo(options) { return this.client.sendOperationRequest({ options }, getAccountInfoOperationSpec); } /** * The Query operation enables users to select/project on blob data by providing simple query * expressions. * @param options The options parameters. */ query(options) { return this.client.sendOperationRequest({ options }, queryOperationSpec); } /** * The Get Tags operation enables users to get the tags associated with a blob. * @param options The options parameters. */ getTags(options) { return this.client.sendOperationRequest({ options }, getTagsOperationSpec); } /** * The Set Tags operation enables users to set tags on a blob. * @param options The options parameters. */ setTags(options) { return this.client.sendOperationRequest({ options }, setTagsOperationSpec); } } // Operation Specifications const xmlSerializer$3 = createSerializer(Mappers, /* isXml */ true); const downloadOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "GET", responses: { 200: { bodyMapper: { type: { name: "Stream" }, serializedName: "parsedResponse", }, headersMapper: BlobDownloadHeaders, }, 206: { bodyMapper: { type: { name: "Stream" }, serializedName: "parsedResponse", }, headersMapper: BlobDownloadHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobDownloadExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, snapshot, versionId, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, range, rangeGetContentMD5, rangeGetContentCRC64, structuredBodyType, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, ], isXML: true, serializer: xmlSerializer$3, }; const getPropertiesOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "HEAD", responses: { 200: { headersMapper: BlobGetPropertiesHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobGetPropertiesExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, snapshot, versionId, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, ], isXML: true, serializer: xmlSerializer$3, }; const deleteOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "DELETE", responses: { 202: { headersMapper: BlobDeleteHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobDeleteExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, snapshot, versionId, blobDeleteType, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, deleteSnapshots, accessTierIfModifiedSince, accessTierIfUnmodifiedSince, ], isXML: true, serializer: xmlSerializer$3, }; const undeleteOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobUndeleteHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobUndeleteExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp8], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$3, }; const setExpiryOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobSetExpiryHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobSetExpiryExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp11], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, expiryOptions, expiresOn, ], isXML: true, serializer: xmlSerializer$3, }; const setHttpHeadersOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobSetHttpHeadersHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobSetHttpHeadersExceptionHeaders, }, }, queryParameters: [comp, timeoutInSeconds], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, blobCacheControl, blobContentType, blobContentMD5, blobContentEncoding, blobContentLanguage, blobContentDisposition, ], isXML: true, serializer: xmlSerializer$3, }; const setImmutabilityPolicyOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobSetImmutabilityPolicyHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobSetImmutabilityPolicyExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, snapshot, versionId, comp12, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifUnmodifiedSince, immutabilityPolicyExpiry, immutabilityPolicyMode, ], isXML: true, serializer: xmlSerializer$3, }; const deleteImmutabilityPolicyOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "DELETE", responses: { 200: { headersMapper: BlobDeleteImmutabilityPolicyHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobDeleteImmutabilityPolicyExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, snapshot, versionId, comp12, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$3, }; const setLegalHoldOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobSetLegalHoldHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobSetLegalHoldExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, snapshot, versionId, comp13, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, legalHold, ], isXML: true, serializer: xmlSerializer$3, }; const setMetadataOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobSetMetadataHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobSetMetadataExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp6], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, metadata, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, encryptionScope, ], isXML: true, serializer: xmlSerializer$3, }; const acquireLeaseOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: BlobAcquireLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobAcquireLeaseExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp10], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, action, duration, proposedLeaseId, ifMatch, ifNoneMatch, ifTags, ], isXML: true, serializer: xmlSerializer$3, }; const releaseLeaseOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobReleaseLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobReleaseLeaseExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp10], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, action1, leaseId1, ifMatch, ifNoneMatch, ifTags, ], isXML: true, serializer: xmlSerializer$3, }; const renewLeaseOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobRenewLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobRenewLeaseExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp10], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, leaseId1, action2, ifMatch, ifNoneMatch, ifTags, ], isXML: true, serializer: xmlSerializer$3, }; const changeLeaseOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobChangeLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobChangeLeaseExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp10], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, leaseId1, action4, proposedLeaseId1, ifMatch, ifNoneMatch, ifTags, ], isXML: true, serializer: xmlSerializer$3, }; const breakLeaseOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 202: { headersMapper: BlobBreakLeaseHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobBreakLeaseExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp10], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, action3, breakPeriod, ifMatch, ifNoneMatch, ifTags, ], isXML: true, serializer: xmlSerializer$3, }; const createSnapshotOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: BlobCreateSnapshotHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobCreateSnapshotExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp14], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, metadata, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, encryptionScope, ], isXML: true, serializer: xmlSerializer$3, }; const startCopyFromURLOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 202: { headersMapper: BlobStartCopyFromURLHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobStartCopyFromURLExceptionHeaders, }, }, queryParameters: [timeoutInSeconds], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, metadata, leaseId, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, immutabilityPolicyExpiry, immutabilityPolicyMode, tier, rehydratePriority, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, sourceIfTags, copySource, blobTagsString, sealBlob, legalHold1, ], isXML: true, serializer: xmlSerializer$3, }; const copyFromURLOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 202: { headersMapper: BlobCopyFromURLHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobCopyFromURLExceptionHeaders, }, }, queryParameters: [timeoutInSeconds], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, metadata, leaseId, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, immutabilityPolicyExpiry, immutabilityPolicyMode, encryptionScope, tier, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, copySource, blobTagsString, legalHold1, xMsRequiresSync, sourceContentMD5, copySourceAuthorization, copySourceTags, fileRequestIntent, ], isXML: true, serializer: xmlSerializer$3, }; const abortCopyFromURLOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 204: { headersMapper: BlobAbortCopyFromURLHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobAbortCopyFromURLExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, comp15, copyId, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, copyActionAbortConstant, ], isXML: true, serializer: xmlSerializer$3, }; const setTierOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: BlobSetTierHeaders, }, 202: { headersMapper: BlobSetTierHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobSetTierExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, snapshot, versionId, comp16, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifTags, rehydratePriority, tier1, ], isXML: true, serializer: xmlSerializer$3, }; const getAccountInfoOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "GET", responses: { 200: { headersMapper: BlobGetAccountInfoHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobGetAccountInfoExceptionHeaders, }, }, queryParameters: [ comp, timeoutInSeconds, restype1, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ], isXML: true, serializer: xmlSerializer$3, }; const queryOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "POST", responses: { 200: { bodyMapper: { type: { name: "Stream" }, serializedName: "parsedResponse", }, headersMapper: BlobQueryHeaders, }, 206: { bodyMapper: { type: { name: "Stream" }, serializedName: "parsedResponse", }, headersMapper: BlobQueryHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobQueryExceptionHeaders, }, }, requestBody: queryRequest, queryParameters: [ timeoutInSeconds, snapshot, comp17, ], urlParameters: [url], headerParameters: [ contentType, accept, version$1, requestId, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "xml", serializer: xmlSerializer$3, }; const getTagsOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "GET", responses: { 200: { bodyMapper: BlobTags, headersMapper: BlobGetTagsHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobGetTagsExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, snapshot, versionId, comp18, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifTags, ifModifiedSince1, ifUnmodifiedSince1, ifMatch1, ifNoneMatch1, ], isXML: true, serializer: xmlSerializer$3, }; const setTagsOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 204: { headersMapper: BlobSetTagsHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlobSetTagsExceptionHeaders, }, }, requestBody: tags, queryParameters: [ timeoutInSeconds, versionId, comp18, ], urlParameters: [url], headerParameters: [ contentType, accept, version$1, requestId, leaseId, ifTags, ifModifiedSince1, ifUnmodifiedSince1, ifMatch1, ifNoneMatch1, transactionalContentMD5, transactionalContentCrc64, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "xml", serializer: xmlSerializer$3, }; /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ /** Class containing PageBlob operations. */ class PageBlobImpl { client; /** * Initialize a new instance of the class PageBlob class. * @param client Reference to the service client */ constructor(client) { this.client = client; } /** * The Create operation creates a new page blob. * @param contentLength The length of the request. * @param blobContentLength This header specifies the maximum size for the page blob, up to 1 TB. The * page blob size must be aligned to a 512-byte boundary. * @param options The options parameters. */ create(contentLength, blobContentLength, options) { return this.client.sendOperationRequest({ contentLength, blobContentLength, options }, createOperationSpec$1); } /** * The Upload Pages operation writes a range of pages to a page blob * @param contentLength The length of the request. * @param body Initial data * @param options The options parameters. */ uploadPages(contentLength, body, options) { return this.client.sendOperationRequest({ contentLength, body, options }, uploadPagesOperationSpec); } /** * The Clear Pages operation clears a set of pages from a page blob * @param contentLength The length of the request. * @param options The options parameters. */ clearPages(contentLength, options) { return this.client.sendOperationRequest({ contentLength, options }, clearPagesOperationSpec); } /** * The Upload Pages operation writes a range of pages to a page blob where the contents are read from a * URL * @param sourceUrl Specify a URL to the copy source. * @param sourceRange Bytes of source data in the specified range. The length of this range should * match the ContentLength header and x-ms-range/Range destination range header. * @param contentLength The length of the request. * @param range The range of bytes to which the source range would be written. The range should be 512 * aligned and range-end is required. * @param options The options parameters. */ uploadPagesFromURL(sourceUrl, sourceRange, contentLength, range, options) { return this.client.sendOperationRequest({ sourceUrl, sourceRange, contentLength, range, options }, uploadPagesFromURLOperationSpec); } /** * The Get Page Ranges operation returns the list of valid page ranges for a page blob or snapshot of a * page blob * @param options The options parameters. */ getPageRanges(options) { return this.client.sendOperationRequest({ options }, getPageRangesOperationSpec); } /** * The Get Page Ranges Diff operation returns the list of valid page ranges for a page blob that were * changed between target blob and previous snapshot. * @param options The options parameters. */ getPageRangesDiff(options) { return this.client.sendOperationRequest({ options }, getPageRangesDiffOperationSpec); } /** * Resize the Blob * @param blobContentLength This header specifies the maximum size for the page blob, up to 1 TB. The * page blob size must be aligned to a 512-byte boundary. * @param options The options parameters. */ resize(blobContentLength, options) { return this.client.sendOperationRequest({ blobContentLength, options }, resizeOperationSpec); } /** * Update the sequence number of the blob * @param sequenceNumberAction Required if the x-ms-blob-sequence-number header is set for the request. * This property applies to page blobs only. This property indicates how the service should modify the * blob's sequence number * @param options The options parameters. */ updateSequenceNumber(sequenceNumberAction, options) { return this.client.sendOperationRequest({ sequenceNumberAction, options }, updateSequenceNumberOperationSpec); } /** * The Copy Incremental operation copies a snapshot of the source page blob to a destination page blob. * The snapshot is copied such that only the differential changes between the previously copied * snapshot are transferred to the destination. The copied snapshots are complete copies of the * original snapshot and can be read or copied from as usual. This API is supported since REST version * 2016-05-31. * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to * 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would * appear in a request URI. The source blob must either be public or must be authenticated via a shared * access signature. * @param options The options parameters. */ copyIncremental(copySource, options) { return this.client.sendOperationRequest({ copySource, options }, copyIncrementalOperationSpec); } } // Operation Specifications const xmlSerializer$2 = createSerializer(Mappers, /* isXml */ true); const createOperationSpec$1 = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: PageBlobCreateHeaders, }, default: { bodyMapper: StorageError, headersMapper: PageBlobCreateExceptionHeaders, }, }, queryParameters: [timeoutInSeconds], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, contentLength, metadata, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, blobCacheControl, blobContentType, blobContentMD5, blobContentEncoding, blobContentLanguage, blobContentDisposition, immutabilityPolicyExpiry, immutabilityPolicyMode, encryptionScope, tier, blobTagsString, legalHold1, blobType, blobContentLength, blobSequenceNumber, ], isXML: true, serializer: xmlSerializer$2, }; const uploadPagesOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: PageBlobUploadPagesHeaders, }, default: { bodyMapper: StorageError, headersMapper: PageBlobUploadPagesExceptionHeaders, }, }, requestBody: body1, queryParameters: [timeoutInSeconds, comp19], urlParameters: [url], headerParameters: [ version$1, requestId, contentLength, leaseId, ifModifiedSince, ifUnmodifiedSince, range, structuredBodyType, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, encryptionScope, transactionalContentMD5, transactionalContentCrc64, contentType1, accept2, pageWrite, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, structuredContentLength, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "binary", serializer: xmlSerializer$2, }; const clearPagesOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: PageBlobClearPagesHeaders, }, default: { bodyMapper: StorageError, headersMapper: PageBlobClearPagesExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp19], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, contentLength, leaseId, ifModifiedSince, ifUnmodifiedSince, range, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, encryptionScope, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, pageWrite1, ], isXML: true, serializer: xmlSerializer$2, }; const uploadPagesFromURLOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: PageBlobUploadPagesFromURLHeaders, }, default: { bodyMapper: StorageError, headersMapper: PageBlobUploadPagesFromURLExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp19], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, contentLength, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, encryptionScope, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, sourceContentMD5, copySourceAuthorization, fileRequestIntent, pageWrite, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, sourceUrl, sourceRange, sourceContentCrc64, range1, sourceEncryptionKey, sourceEncryptionKeySha256, sourceEncryptionAlgorithm, ], isXML: true, serializer: xmlSerializer$2, }; const getPageRangesOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "GET", responses: { 200: { bodyMapper: PageList, headersMapper: PageBlobGetPageRangesHeaders, }, default: { bodyMapper: StorageError, headersMapper: PageBlobGetPageRangesExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, marker, maxPageSize, snapshot, comp20, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, range, ifMatch, ifNoneMatch, ifTags, ], isXML: true, serializer: xmlSerializer$2, }; const getPageRangesDiffOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "GET", responses: { 200: { bodyMapper: PageList, headersMapper: PageBlobGetPageRangesDiffHeaders, }, default: { bodyMapper: StorageError, headersMapper: PageBlobGetPageRangesDiffExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, marker, maxPageSize, snapshot, comp20, prevsnapshot, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, range, ifMatch, ifNoneMatch, ifTags, prevSnapshotUrl, ], isXML: true, serializer: xmlSerializer$2, }; const resizeOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: PageBlobResizeHeaders, }, default: { bodyMapper: StorageError, headersMapper: PageBlobResizeExceptionHeaders, }, }, queryParameters: [comp, timeoutInSeconds], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, encryptionScope, blobContentLength, ], isXML: true, serializer: xmlSerializer$2, }; const updateSequenceNumberOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: PageBlobUpdateSequenceNumberHeaders, }, default: { bodyMapper: StorageError, headersMapper: PageBlobUpdateSequenceNumberExceptionHeaders, }, }, queryParameters: [comp, timeoutInSeconds], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, blobSequenceNumber, sequenceNumberAction, ], isXML: true, serializer: xmlSerializer$2, }; const copyIncrementalOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 202: { headersMapper: PageBlobCopyIncrementalHeaders, }, default: { bodyMapper: StorageError, headersMapper: PageBlobCopyIncrementalExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp21], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ifTags, copySource, ], isXML: true, serializer: xmlSerializer$2, }; /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ /** Class containing AppendBlob operations. */ class AppendBlobImpl { client; /** * Initialize a new instance of the class AppendBlob class. * @param client Reference to the service client */ constructor(client) { this.client = client; } /** * The Create Append Blob operation creates a new append blob. * @param contentLength The length of the request. * @param options The options parameters. */ create(contentLength, options) { return this.client.sendOperationRequest({ contentLength, options }, createOperationSpec); } /** * The Append Block operation commits a new block of data to the end of an existing append blob. The * Append Block operation is permitted only if the blob was created with x-ms-blob-type set to * AppendBlob. Append Block is supported only on version 2015-02-21 version or later. * @param contentLength The length of the request. * @param body Initial data * @param options The options parameters. */ appendBlock(contentLength, body, options) { return this.client.sendOperationRequest({ contentLength, body, options }, appendBlockOperationSpec); } /** * The Append Block operation commits a new block of data to the end of an existing append blob where * the contents are read from a source url. The Append Block operation is permitted only if the blob * was created with x-ms-blob-type set to AppendBlob. Append Block is supported only on version * 2015-02-21 version or later. * @param sourceUrl Specify a URL to the copy source. * @param contentLength The length of the request. * @param options The options parameters. */ appendBlockFromUrl(sourceUrl, contentLength, options) { return this.client.sendOperationRequest({ sourceUrl, contentLength, options }, appendBlockFromUrlOperationSpec); } /** * The Seal operation seals the Append Blob to make it read-only. Seal is supported only on version * 2019-12-12 version or later. * @param options The options parameters. */ seal(options) { return this.client.sendOperationRequest({ options }, sealOperationSpec); } } // Operation Specifications const xmlSerializer$1 = createSerializer(Mappers, /* isXml */ true); const createOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: AppendBlobCreateHeaders, }, default: { bodyMapper: StorageError, headersMapper: AppendBlobCreateExceptionHeaders, }, }, queryParameters: [timeoutInSeconds], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, contentLength, metadata, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, blobCacheControl, blobContentType, blobContentMD5, blobContentEncoding, blobContentLanguage, blobContentDisposition, immutabilityPolicyExpiry, immutabilityPolicyMode, encryptionScope, blobTagsString, legalHold1, blobType1, ], isXML: true, serializer: xmlSerializer$1, }; const appendBlockOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: AppendBlobAppendBlockHeaders, }, default: { bodyMapper: StorageError, headersMapper: AppendBlobAppendBlockExceptionHeaders, }, }, requestBody: body1, queryParameters: [timeoutInSeconds, comp22], urlParameters: [url], headerParameters: [ version$1, requestId, contentLength, leaseId, ifModifiedSince, ifUnmodifiedSince, structuredBodyType, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, encryptionScope, transactionalContentMD5, transactionalContentCrc64, contentType1, accept2, structuredContentLength, maxSize, appendPosition, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "binary", serializer: xmlSerializer$1, }; const appendBlockFromUrlOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: AppendBlobAppendBlockFromUrlHeaders, }, default: { bodyMapper: StorageError, headersMapper: AppendBlobAppendBlockFromUrlExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp22], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, contentLength, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, encryptionScope, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, sourceContentMD5, copySourceAuthorization, fileRequestIntent, transactionalContentMD5, sourceUrl, sourceContentCrc64, sourceEncryptionKey, sourceEncryptionKeySha256, sourceEncryptionAlgorithm, maxSize, appendPosition, sourceRange1, ], isXML: true, serializer: xmlSerializer$1, }; const sealOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 200: { headersMapper: AppendBlobSealHeaders, }, default: { bodyMapper: StorageError, headersMapper: AppendBlobSealExceptionHeaders, }, }, queryParameters: [timeoutInSeconds, comp23], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, appendPosition, ], isXML: true, serializer: xmlSerializer$1, }; /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ /** Class containing BlockBlob operations. */ class BlockBlobImpl { client; /** * Initialize a new instance of the class BlockBlob class. * @param client Reference to the service client */ constructor(client) { this.client = client; } /** * The Upload Block Blob operation updates the content of an existing block blob. Updating an existing * block blob overwrites any existing metadata on the blob. Partial updates are not supported with Put * Blob; the content of the existing blob is overwritten with the content of the new blob. To perform a * partial update of the content of a block blob, use the Put Block List operation. * @param contentLength The length of the request. * @param body Initial data * @param options The options parameters. */ upload(contentLength, body, options) { return this.client.sendOperationRequest({ contentLength, body, options }, uploadOperationSpec); } /** * The Put Blob from URL operation creates a new Block Blob where the contents of the blob are read * from a given URL. This API is supported beginning with the 2020-04-08 version. Partial updates are * not supported with Put Blob from URL; the content of an existing blob is overwritten with the * content of the new blob. To perform partial updates to a block blob’s contents using a source URL, * use the Put Block from URL API in conjunction with Put Block List. * @param contentLength The length of the request. * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to * 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would * appear in a request URI. The source blob must either be public or must be authenticated via a shared * access signature. * @param options The options parameters. */ putBlobFromUrl(contentLength, copySource, options) { return this.client.sendOperationRequest({ contentLength, copySource, options }, putBlobFromUrlOperationSpec); } /** * The Stage Block operation creates a new block to be committed as part of a blob * @param blockId A valid Base64 string value that identifies the block. Prior to encoding, the string * must be less than or equal to 64 bytes in size. For a given blob, the length of the value specified * for the blockid parameter must be the same size for each block. * @param contentLength The length of the request. * @param body Initial data * @param options The options parameters. */ stageBlock(blockId, contentLength, body, options) { return this.client.sendOperationRequest({ blockId, contentLength, body, options }, stageBlockOperationSpec); } /** * The Stage Block operation creates a new block to be committed as part of a blob where the contents * are read from a URL. * @param blockId A valid Base64 string value that identifies the block. Prior to encoding, the string * must be less than or equal to 64 bytes in size. For a given blob, the length of the value specified * for the blockid parameter must be the same size for each block. * @param contentLength The length of the request. * @param sourceUrl Specify a URL to the copy source. * @param options The options parameters. */ stageBlockFromURL(blockId, contentLength, sourceUrl, options) { return this.client.sendOperationRequest({ blockId, contentLength, sourceUrl, options }, stageBlockFromURLOperationSpec); } /** * The Commit Block List operation writes a blob by specifying the list of block IDs that make up the * blob. In order to be written as part of a blob, a block must have been successfully written to the * server in a prior Put Block operation. You can call Put Block List to update a blob by uploading * only those blocks that have changed, then committing the new and existing blocks together. You can * do this by specifying whether to commit a block from the committed block list or from the * uncommitted block list, or to commit the most recently uploaded version of the block, whichever list * it may belong to. * @param blocks Blob Blocks. * @param options The options parameters. */ commitBlockList(blocks, options) { return this.client.sendOperationRequest({ blocks, options }, commitBlockListOperationSpec); } /** * The Get Block List operation retrieves the list of blocks that have been uploaded as part of a block * blob * @param listType Specifies whether to return the list of committed blocks, the list of uncommitted * blocks, or both lists together. * @param options The options parameters. */ getBlockList(listType, options) { return this.client.sendOperationRequest({ listType, options }, getBlockListOperationSpec); } } // Operation Specifications const xmlSerializer = createSerializer(Mappers, /* isXml */ true); const uploadOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: BlockBlobUploadHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlockBlobUploadExceptionHeaders, }, }, requestBody: body1, queryParameters: [timeoutInSeconds], urlParameters: [url], headerParameters: [ version$1, requestId, contentLength, metadata, leaseId, ifModifiedSince, ifUnmodifiedSince, structuredBodyType, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, blobCacheControl, blobContentType, blobContentMD5, blobContentEncoding, blobContentLanguage, blobContentDisposition, immutabilityPolicyExpiry, immutabilityPolicyMode, encryptionScope, tier, blobTagsString, legalHold1, transactionalContentMD5, transactionalContentCrc64, contentType1, accept2, structuredContentLength, blobType2, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "binary", serializer: xmlSerializer, }; const putBlobFromUrlOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: BlockBlobPutBlobFromUrlHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlockBlobPutBlobFromUrlExceptionHeaders, }, }, queryParameters: [timeoutInSeconds], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, contentLength, metadata, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, blobCacheControl, blobContentType, blobContentMD5, blobContentEncoding, blobContentLanguage, blobContentDisposition, encryptionScope, tier, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, sourceIfTags, copySource, blobTagsString, sourceContentMD5, copySourceAuthorization, copySourceTags, fileRequestIntent, transactionalContentMD5, sourceEncryptionKey, sourceEncryptionKeySha256, sourceEncryptionAlgorithm, blobType2, copySourceBlobProperties, ], isXML: true, serializer: xmlSerializer, }; const stageBlockOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: BlockBlobStageBlockHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlockBlobStageBlockExceptionHeaders, }, }, requestBody: body1, queryParameters: [ timeoutInSeconds, comp24, blockId, ], urlParameters: [url], headerParameters: [ version$1, requestId, contentLength, leaseId, structuredBodyType, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, transactionalContentMD5, transactionalContentCrc64, contentType1, accept2, structuredContentLength, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "binary", serializer: xmlSerializer, }; const stageBlockFromURLOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: BlockBlobStageBlockFromURLHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlockBlobStageBlockFromURLExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, comp24, blockId, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, contentLength, leaseId, encryptionKey, encryptionKeySha256, encryptionAlgorithm, encryptionScope, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, sourceContentMD5, copySourceAuthorization, fileRequestIntent, sourceUrl, sourceContentCrc64, sourceEncryptionKey, sourceEncryptionKeySha256, sourceEncryptionAlgorithm, sourceRange1, ], isXML: true, serializer: xmlSerializer, }; const commitBlockListOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "PUT", responses: { 201: { headersMapper: BlockBlobCommitBlockListHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlockBlobCommitBlockListExceptionHeaders, }, }, requestBody: blocks, queryParameters: [timeoutInSeconds, comp25], urlParameters: [url], headerParameters: [ contentType, accept, version$1, requestId, metadata, leaseId, ifModifiedSince, ifUnmodifiedSince, encryptionKey, encryptionKeySha256, encryptionAlgorithm, ifMatch, ifNoneMatch, ifTags, blobCacheControl, blobContentType, blobContentMD5, blobContentEncoding, blobContentLanguage, blobContentDisposition, immutabilityPolicyExpiry, immutabilityPolicyMode, encryptionScope, tier, blobTagsString, legalHold1, transactionalContentMD5, transactionalContentCrc64, ], isXML: true, contentType: "application/xml; charset=utf-8", mediaType: "xml", serializer: xmlSerializer, }; const getBlockListOperationSpec = { path: "/{containerName}/{blob}", httpMethod: "GET", responses: { 200: { bodyMapper: BlockList, headersMapper: BlockBlobGetBlockListHeaders, }, default: { bodyMapper: StorageError, headersMapper: BlockBlobGetBlockListExceptionHeaders, }, }, queryParameters: [ timeoutInSeconds, snapshot, comp25, listType, ], urlParameters: [url], headerParameters: [ version$1, requestId, accept1, leaseId, ifTags, ], isXML: true, serializer: xmlSerializer, }; /* * Copyright (c) Microsoft Corporation. * Licensed under the MIT License. * * Code generated by Microsoft (R) AutoRest Code Generator. * Changes may cause incorrect behavior and will be lost if the code is regenerated. */ let StorageClient$1 = class StorageClient extends ExtendedServiceClient { url; version; /** * Initializes a new instance of the StorageClient class. * @param url The URL of the service account, container, or blob that is the target of the desired * operation. * @param options The parameter options */ constructor(url, options) { if (url === undefined) { throw new Error("'url' cannot be null"); } // Initializing default values for options if (!options) { options = {}; } const defaults = { requestContentType: "application/json; charset=utf-8", }; const packageDetails = `azsdk-js-azure-storage-blob/12.32.0`; const userAgentPrefix = options.userAgentOptions && options.userAgentOptions.userAgentPrefix ? `${options.userAgentOptions.userAgentPrefix} ${packageDetails}` : `${packageDetails}`; const optionsWithDefaults = { ...defaults, ...options, userAgentOptions: { userAgentPrefix, }, endpoint: options.endpoint ?? options.baseUri ?? "{url}", }; super(optionsWithDefaults); // Parameter assignments this.url = url; // Assigning values to Constant parameters this.version = options.version || "2026-04-06"; this.service = new ServiceImpl(this); this.container = new ContainerImpl(this); this.blob = new BlobImpl(this); this.pageBlob = new PageBlobImpl(this); this.appendBlob = new AppendBlobImpl(this); this.blockBlob = new BlockBlobImpl(this); } service; container; blob; pageBlob; appendBlob; blockBlob; }; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * @internal */ class StorageContextClient extends StorageClient$1 { async sendOperationRequest(operationArguments, operationSpec) { const operationSpecToSend = { ...operationSpec }; if (operationSpecToSend.path === "/{containerName}" || operationSpecToSend.path === "/{containerName}/{blob}") { operationSpecToSend.path = ""; } return super.sendOperationRequest(operationArguments, operationSpecToSend); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Reserved URL characters must be properly escaped for Storage services like Blob or File. * * ## URL encode and escape strategy for JS SDKs * * When customers pass a URL string into XxxClient classes constructor, the URL string may already be URL encoded or not. * But before sending to Azure Storage server, the URL must be encoded. However, it's hard for a SDK to guess whether the URL * string has been encoded or not. We have 2 potential strategies, and chose strategy two for the XxxClient constructors. * * ### Strategy One: Assume the customer URL string is not encoded, and always encode URL string in SDK. * * This is what legacy V2 SDK does, simple and works for most of the cases. * - When customer URL string is "http://account.blob.core.windows.net/con/b:", * SDK will encode it to "http://account.blob.core.windows.net/con/b%3A" and send to server. A blob named "b:" will be created. * - When customer URL string is "http://account.blob.core.windows.net/con/b%3A", * SDK will encode it to "http://account.blob.core.windows.net/con/b%253A" and send to server. A blob named "b%3A" will be created. * * But this strategy will make it not possible to create a blob with "?" in it's name. Because when customer URL string is * "http://account.blob.core.windows.net/con/blob?name", the "?name" will be treated as URL paramter instead of blob name. * If customer URL string is "http://account.blob.core.windows.net/con/blob%3Fname", a blob named "blob%3Fname" will be created. * V2 SDK doesn't have this issue because it doesn't allow customer pass in a full URL, it accepts a separate blob name and encodeURIComponent for it. * We cannot accept a SDK cannot create a blob name with "?". So we implement strategy two: * * ### Strategy Two: SDK doesn't assume the URL has been encoded or not. It will just escape the special characters. * * This is what V10 Blob Go SDK does. It accepts a URL type in Go, and call url.EscapedPath() to escape the special chars unescaped. * - When customer URL string is "http://account.blob.core.windows.net/con/b:", * SDK will escape ":" like "http://account.blob.core.windows.net/con/b%3A" and send to server. A blob named "b:" will be created. * - When customer URL string is "http://account.blob.core.windows.net/con/b%3A", * There is no special characters, so send "http://account.blob.core.windows.net/con/b%3A" to server. A blob named "b:" will be created. * - When customer URL string is "http://account.blob.core.windows.net/con/b%253A", * There is no special characters, so send "http://account.blob.core.windows.net/con/b%253A" to server. A blob named "b%3A" will be created. * * This strategy gives us flexibility to create with any special characters. But "%" will be treated as a special characters, if the URL string * is not encoded, there shouldn't a "%" in the URL string, otherwise the URL is not a valid URL. * If customer needs to create a blob with "%" in it's blob name, use "%25" instead of "%". Just like above 3rd sample. * And following URL strings are invalid: * - "http://account.blob.core.windows.net/con/b%" * - "http://account.blob.core.windows.net/con/b%2" * - "http://account.blob.core.windows.net/con/b%G" * * Another special character is "?", use "%2F" to represent a blob name with "?" in a URL string. * * ### Strategy for containerName, blobName or other specific XXXName parameters in methods such as `containerClient.getBlobClient(blobName)` * * We will apply strategy one, and call encodeURIComponent for these parameters like blobName. Because what customers passes in is a plain name instead of a URL. * * @see https://learn.microsoft.com/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata * @see https://learn.microsoft.com/rest/api/storageservices/naming-and-referencing-shares--directories--files--and-metadata * * @param url - */ function escapeURLPath(url) { const urlParsed = new URL(url); let path = urlParsed.pathname; path = path || "/"; path = escape(path); urlParsed.pathname = path; return urlParsed.toString(); } function getProxyUriFromDevConnString(connectionString) { // Development Connection String // https://learn.microsoft.com/azure/storage/common/storage-configure-connection-string#connect-to-the-emulator-account-using-the-well-known-account-name-and-key let proxyUri = ""; if (connectionString.search("DevelopmentStorageProxyUri=") !== -1) { // CONNECTION_STRING=UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://myProxyUri const matchCredentials = connectionString.split(";"); for (const element of matchCredentials) { if (element.trim().startsWith("DevelopmentStorageProxyUri=")) { proxyUri = element.trim().match("DevelopmentStorageProxyUri=(.*)")[1]; } } } return proxyUri; } function getValueInConnString(connectionString, argument) { const elements = connectionString.split(";"); for (const element of elements) { if (element.trim().startsWith(argument)) { return element.trim().match(argument + "=(.*)")[1]; } } return ""; } /** * Extracts the parts of an Azure Storage account connection string. * * @param connectionString - Connection string. * @returns String key value pairs of the storage account's url and credentials. */ function extractConnectionStringParts(connectionString) { let proxyUri = ""; if (connectionString.startsWith("UseDevelopmentStorage=true")) { // Development connection string proxyUri = getProxyUriFromDevConnString(connectionString); connectionString = DevelopmentConnectionString; } // Matching BlobEndpoint in the Account connection string let blobEndpoint = getValueInConnString(connectionString, "BlobEndpoint"); // Slicing off '/' at the end if exists // (The methods that use `extractConnectionStringParts` expect the url to not have `/` at the end) blobEndpoint = blobEndpoint.endsWith("/") ? blobEndpoint.slice(0, -1) : blobEndpoint; if (connectionString.search("DefaultEndpointsProtocol=") !== -1 && connectionString.search("AccountKey=") !== -1) { // Account connection string let defaultEndpointsProtocol = ""; let accountName = ""; let accountKey = Buffer.from("accountKey", "base64"); let endpointSuffix = ""; // Get account name and key accountName = getValueInConnString(connectionString, "AccountName"); accountKey = Buffer.from(getValueInConnString(connectionString, "AccountKey"), "base64"); if (!blobEndpoint) { // BlobEndpoint is not present in the Account connection string // Can be obtained from `${defaultEndpointsProtocol}://${accountName}.blob.${endpointSuffix}` defaultEndpointsProtocol = getValueInConnString(connectionString, "DefaultEndpointsProtocol"); const protocol = defaultEndpointsProtocol.toLowerCase(); if (protocol !== "https" && protocol !== "http") { throw new Error("Invalid DefaultEndpointsProtocol in the provided Connection String. Expecting 'https' or 'http'"); } endpointSuffix = getValueInConnString(connectionString, "EndpointSuffix"); if (!endpointSuffix) { throw new Error("Invalid EndpointSuffix in the provided Connection String"); } blobEndpoint = `${defaultEndpointsProtocol}://${accountName}.blob.${endpointSuffix}`; } if (!accountName) { throw new Error("Invalid AccountName in the provided Connection String"); } else if (accountKey.length === 0) { throw new Error("Invalid AccountKey in the provided Connection String"); } return { kind: "AccountConnString", url: blobEndpoint, accountName, accountKey, proxyUri, }; } else { // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); let accountName = getValueInConnString(connectionString, "AccountName"); // if accountName is empty, try to read it from BlobEndpoint if (!accountName) { accountName = getAccountNameFromUrl(blobEndpoint); } if (!blobEndpoint) { throw new Error("Invalid BlobEndpoint in the provided SAS Connection String"); } else if (!accountSas) { throw new Error("Invalid SharedAccessSignature in the provided SAS Connection String"); } // client constructors assume accountSas does *not* start with ? if (accountSas.startsWith("?")) { accountSas = accountSas.substring(1); } return { kind: "SASConnString", url: blobEndpoint, accountName, accountSas }; } } /** * Internal escape method implemented Strategy Two mentioned in escapeURL() description. * * @param text - */ function escape(text) { return encodeURIComponent(text) .replace(/%2F/g, "/") // Don't escape for "/" .replace(/'/g, "%27") // Escape for "'" .replace(/\+/g, "%20") .replace(/%25/g, "%"); // Revert encoded "%" } /** * Append a string to URL path. Will remove duplicated "/" in front of the string * when URL path ends with a "/". * * @param url - Source URL string * @param name - String to be appended to URL * @returns An updated URL string */ function appendToURLPath(url, name) { const urlParsed = new URL(url); let path = urlParsed.pathname; path = path ? (path.endsWith("/") ? `${path}${name}` : `${path}/${name}`) : name; urlParsed.pathname = path; return urlParsed.toString(); } /** * Set URL parameter name and value. If name exists in URL parameters, old value * will be replaced by name key. If not provide value, the parameter will be deleted. * * @param url - Source URL string * @param name - Parameter name * @param value - Parameter value * @returns An updated URL string */ function setURLParameter(url, name, value) { const urlParsed = new URL(url); const encodedName = encodeURIComponent(name); const encodedValue = value ? encodeURIComponent(value) : undefined; // mutating searchParams will change the encoding, so we have to do this ourselves const searchString = urlParsed.search === "" ? "?" : urlParsed.search; const searchPieces = []; for (const pair of searchString.slice(1).split("&")) { if (pair) { const [key] = pair.split("=", 2); if (key !== encodedName) { searchPieces.push(pair); } } } if (encodedValue) { searchPieces.push(`${encodedName}=${encodedValue}`); } urlParsed.search = searchPieces.length ? `?${searchPieces.join("&")}` : ""; return urlParsed.toString(); } /** * Get URL parameter by name. * * @param url - * @param name - */ function getURLParameter(url, name) { const urlParsed = new URL(url); return urlParsed.searchParams.get(name) ?? undefined; } /** * Get URL scheme from an URL string. * * @param url - Source URL string */ function getURLScheme(url) { try { const urlParsed = new URL(url); return urlParsed.protocol.endsWith(":") ? urlParsed.protocol.slice(0, -1) : urlParsed.protocol; } catch (e) { return undefined; } } /** * Append a string to URL query. * * @param url - Source URL string. * @param queryParts - String to be appended to the URL query. * @returns An updated URL string. */ function appendToURLQuery(url, queryParts) { const urlParsed = new URL(url); let query = urlParsed.search; if (query) { query += "&" + queryParts; } else { query = queryParts; } urlParsed.search = query; return urlParsed.toString(); } /** * Rounds a date off to seconds. * * @param date - * @param withMilliseconds - If true, YYYY-MM-DDThh:mm:ss.fffffffZ will be returned; * If false, YYYY-MM-DDThh:mm:ssZ will be returned. * @returns Date string in ISO8061 format, with or without 7 milliseconds component */ function truncatedISO8061Date(date, withMilliseconds = true) { // Date.toISOString() will return like "2018-10-29T06:34:36.139Z" const dateString = date.toISOString(); return withMilliseconds ? dateString.substring(0, dateString.length - 1) + "0000" + "Z" : dateString.substring(0, dateString.length - 5) + "Z"; } /** * Base64 encode. * * @param content - */ function base64encode$1(content) { return Buffer.from(content).toString("base64"); } /** * Generate a 64 bytes base64 block ID string. * * @param blockIndex - */ function generateBlockID(blockIDPrefix, blockIndex) { // To generate a 64 bytes base64 string, source string should be 48 const maxSourceStringLength = 48; // A blob can have a maximum of 100,000 uncommitted blocks at any given time const maxBlockIndexLength = 6; const maxAllowedBlockIDPrefixLength = maxSourceStringLength - maxBlockIndexLength; if (blockIDPrefix.length > maxAllowedBlockIDPrefixLength) { blockIDPrefix = blockIDPrefix.slice(0, maxAllowedBlockIDPrefixLength); } const res = blockIDPrefix + padStart(blockIndex.toString(), maxSourceStringLength - blockIDPrefix.length, "0"); return base64encode$1(res); } /** * String.prototype.padStart() * * @param currentString - * @param targetLength - * @param padString - */ function padStart(currentString, targetLength, padString = " ") { // @ts-expect-error: TS doesn't know this code needs to run downlevel sometimes if (String.prototype.padStart) { return currentString.padStart(targetLength, padString); } padString = padString || " "; if (currentString.length > targetLength) { return currentString; } else { targetLength = targetLength - currentString.length; if (targetLength > padString.length) { padString += padString.repeat(targetLength / padString.length); } return padString.slice(0, targetLength) + currentString; } } /** * If two strings are equal when compared case insensitive. * * @param str1 - * @param str2 - */ function iEqual(str1, str2) { return str1.toLocaleLowerCase() === str2.toLocaleLowerCase(); } /** * Extracts account name from the url * @param url - url to extract the account name from * @returns with the account name */ function getAccountNameFromUrl(url) { const parsedUrl = new URL(url); let accountName; try { if (parsedUrl.hostname.split(".")[1] === "blob") { // `${defaultEndpointsProtocol}://${accountName}.blob.${endpointSuffix}`; accountName = parsedUrl.hostname.split(".")[0]; } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/ // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/ // .getPath() -> /devstoreaccount1/ accountName = parsedUrl.pathname.split("/")[1]; } else { // Custom domain case: "https://customdomain.com/containername/blob". accountName = ""; } return accountName; } catch (error) { throw new Error("Unable to extract accountName with provided information."); } } function isIpEndpointStyle(parsedUrl) { const host = parsedUrl.host; // Case 1: Ipv6, use a broad regex to find out candidates whose host contains two ':'. // Case 2: localhost(:port) or host.docker.internal, use broad regex to match port part. // Case 3: Ipv4, use broad regex which just check if host contains Ipv4. // For valid host please refer to https://man7.org/linux/man-pages/man7/hostname.7.html. return (/^.*:.*:.*$|^(localhost|host.docker.internal)(:[0-9]+)?$|^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])){3}(:[0-9]+)?$/.test(host) || (Boolean(parsedUrl.port) && PathStylePorts.includes(parsedUrl.port))); } /** * Convert Tags to encoded string. * * @param tags - */ function toBlobTagsString(tags) { if (tags === undefined) { return undefined; } const tagPairs = []; for (const key in tags) { if (Object.prototype.hasOwnProperty.call(tags, key)) { const value = tags[key]; tagPairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); } } return tagPairs.join("&"); } /** * Convert Tags type to BlobTags. * * @param tags - */ function toBlobTags(tags) { if (tags === undefined) { return undefined; } const res = { blobTagSet: [], }; for (const key in tags) { if (Object.prototype.hasOwnProperty.call(tags, key)) { const value = tags[key]; res.blobTagSet.push({ key, value, }); } } return res; } /** * Covert BlobTags to Tags type. * * @param tags - */ function toTags(tags) { if (tags === undefined) { return undefined; } const res = {}; for (const blobTag of tags.blobTagSet) { res[blobTag.key] = blobTag.value; } return res; } /** * Convert BlobQueryTextConfiguration to QuerySerialization type. * * @param textConfiguration - */ function toQuerySerialization(textConfiguration) { if (textConfiguration === undefined) { return undefined; } switch (textConfiguration.kind) { case "csv": return { format: { type: "delimited", delimitedTextConfiguration: { columnSeparator: textConfiguration.columnSeparator || ",", fieldQuote: textConfiguration.fieldQuote || "", recordSeparator: textConfiguration.recordSeparator, escapeChar: textConfiguration.escapeCharacter || "", headersPresent: textConfiguration.hasHeaders || false, }, }, }; case "json": return { format: { type: "json", jsonTextConfiguration: { recordSeparator: textConfiguration.recordSeparator, }, }, }; case "arrow": return { format: { type: "arrow", arrowConfiguration: { schema: textConfiguration.schema, }, }, }; case "parquet": return { format: { type: "parquet", }, }; default: throw Error("Invalid BlobQueryTextConfiguration."); } } function parseObjectReplicationRecord(objectReplicationRecord) { if (!objectReplicationRecord) { return undefined; } if ("policy-id" in objectReplicationRecord) { // If the dictionary contains a key with policy id, we are not required to do any parsing since // the policy id should already be stored in the ObjectReplicationDestinationPolicyId. return undefined; } const orProperties = []; for (const key in objectReplicationRecord) { const ids = key.split("_"); const policyPrefix = "or-"; if (ids[0].startsWith(policyPrefix)) { ids[0] = ids[0].substring(policyPrefix.length); } const rule = { ruleId: ids[1], replicationStatus: objectReplicationRecord[key], }; const policyIndex = orProperties.findIndex((policy) => policy.policyId === ids[0]); if (policyIndex > -1) { orProperties[policyIndex].rules.push(rule); } else { orProperties.push({ policyId: ids[0], rules: [rule], }); } } return orProperties; } function httpAuthorizationToString(httpAuthorization) { return httpAuthorization ? httpAuthorization.scheme + " " + httpAuthorization.value : undefined; } function* ExtractPageRangeInfoItems(getPageRangesSegment) { let pageRange = []; let clearRange = []; if (getPageRangesSegment.pageRange) pageRange = getPageRangesSegment.pageRange; if (getPageRangesSegment.clearRange) clearRange = getPageRangesSegment.clearRange; let pageRangeIndex = 0; let clearRangeIndex = 0; while (pageRangeIndex < pageRange.length && clearRangeIndex < clearRange.length) { if (pageRange[pageRangeIndex].start < clearRange[clearRangeIndex].start) { yield { start: pageRange[pageRangeIndex].start, end: pageRange[pageRangeIndex].end, isClear: false, }; ++pageRangeIndex; } else { yield { start: clearRange[clearRangeIndex].start, end: clearRange[clearRangeIndex].end, isClear: true, }; ++clearRangeIndex; } } for (; pageRangeIndex < pageRange.length; ++pageRangeIndex) { yield { start: pageRange[pageRangeIndex].start, end: pageRange[pageRangeIndex].end, isClear: false, }; } for (; clearRangeIndex < clearRange.length; ++clearRangeIndex) { yield { start: clearRange[clearRangeIndex].start, end: clearRange[clearRangeIndex].end, isClear: true, }; } } /** * A typesafe helper for ensuring that a given response object has * the original _response attached. * @param response - A response object from calling a client operation * @returns The same object, but with known _response property */ function assertResponse(response) { if (`_response` in response) { return response; } throw new TypeError(`Unexpected response object ${response}`); } async function setUploadChecksumParameters(body, contentLength, parameters, uploadOptions, configContentChecksumAlgorithm) { let contentChecksumAlgorithm = uploadOptions.contentChecksumAlgorithm ?? configContentChecksumAlgorithm; if (contentChecksumAlgorithm === undefined) { contentChecksumAlgorithm = "Customized"; } if (contentChecksumAlgorithm === "Auto") { contentChecksumAlgorithm = "StorageCrc64"; } let bodyInfo = undefined; if (contentChecksumAlgorithm === "Customized") { parameters.transactionalContentMD5 = uploadOptions.transactionalContentMD5; parameters.transactionalContentCrc64 = uploadOptions.transactionalContentCrc64; } else if (contentChecksumAlgorithm === "StorageCrc64") { await StorageCRC64Calculator.init(); bodyInfo = await structuredMessageEncoding(body, contentLength); parameters.structuredBodyType = "XSM/1.0; properties=crc64"; parameters.structuredContentLength = contentLength; } return { body: contentChecksumAlgorithm === "StorageCrc64" ? bodyInfo.body : body, contentLength: contentChecksumAlgorithm === "StorageCrc64" ? bodyInfo.encodedContentLength : contentLength, contentChecksumAlgorithm: contentChecksumAlgorithm, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A StorageClient represents a based URL class for {@link BlobServiceClient}, {@link ContainerClient} * and etc. */ class StorageClient { /** * Encoded URL string value. */ url; accountName; /** * Request policy pipeline. * * @internal */ pipeline; /** * Such as AnonymousCredential, StorageSharedKeyCredential or any credential from the `@azure/identity` package to authenticate requests to the service. You can also provide an object that implements the TokenCredential interface. If not specified, AnonymousCredential is used. */ credential; /** * StorageClient is a reference to protocol layer operations entry, which is * generated by AutoRest generator. */ storageClientContext; /** */ isHttps; /** * Creates an instance of StorageClient. * @param url - url to resource * @param pipeline - request policy pipeline. */ constructor(url, pipeline) { // URL should be encoded and only once, protocol layer shouldn't encode URL again this.url = escapeURLPath(url); this.accountName = getAccountNameFromUrl(url); this.pipeline = pipeline; this.storageClientContext = new StorageContextClient(this.url, getCoreClientOptions(pipeline)); this.isHttps = iEqual(getURLScheme(this.url) || "", "https"); this.credential = getCredentialFromPipeline(pipeline); // Override protocol layer's default content-type const storageClientContext = this.storageClientContext; storageClientContext.requestContentType = undefined; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Creates a span using the global tracer. * @internal */ const tracingClient = createTracingClient({ packageName: "@azure/storage-blob", packageVersion: SDK_VERSION, namespace: "Microsoft.Storage", }); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * This is a helper class to construct a string representing the permissions granted by a ServiceSAS to a blob. Setting * a value to true means that any SAS which uses these permissions will grant permissions for that operation. Once all * the values are set, this should be serialized with toString and set as the permissions field on a * {@link BlobSASSignatureValues} object. It is possible to construct the permissions string without this class, but * the order of the permissions is particular and this class guarantees correctness. */ class BlobSASPermissions { /** * Creates a {@link BlobSASPermissions} from the specified permissions string. This method will throw an * Error if it encounters a character that does not correspond to a valid permission. * * @param permissions - */ static parse(permissions) { const blobSASPermissions = new BlobSASPermissions(); for (const char of permissions) { switch (char) { case "r": blobSASPermissions.read = true; break; case "a": blobSASPermissions.add = true; break; case "c": blobSASPermissions.create = true; break; case "w": blobSASPermissions.write = true; break; case "d": blobSASPermissions.delete = true; break; case "x": blobSASPermissions.deleteVersion = true; break; case "t": blobSASPermissions.tag = true; break; case "m": blobSASPermissions.move = true; break; case "e": blobSASPermissions.execute = true; break; case "i": blobSASPermissions.setImmutabilityPolicy = true; break; case "y": blobSASPermissions.permanentDelete = true; break; default: throw new RangeError(`Invalid permission: ${char}`); } } return blobSASPermissions; } /** * Creates a {@link BlobSASPermissions} from a raw object which contains same keys as it * and boolean values for them. * * @param permissionLike - */ static from(permissionLike) { const blobSASPermissions = new BlobSASPermissions(); if (permissionLike.read) { blobSASPermissions.read = true; } if (permissionLike.add) { blobSASPermissions.add = true; } if (permissionLike.create) { blobSASPermissions.create = true; } if (permissionLike.write) { blobSASPermissions.write = true; } if (permissionLike.delete) { blobSASPermissions.delete = true; } if (permissionLike.deleteVersion) { blobSASPermissions.deleteVersion = true; } if (permissionLike.tag) { blobSASPermissions.tag = true; } if (permissionLike.move) { blobSASPermissions.move = true; } if (permissionLike.execute) { blobSASPermissions.execute = true; } if (permissionLike.setImmutabilityPolicy) { blobSASPermissions.setImmutabilityPolicy = true; } if (permissionLike.permanentDelete) { blobSASPermissions.permanentDelete = true; } return blobSASPermissions; } /** * Specifies Read access granted. */ read = false; /** * Specifies Add access granted. */ add = false; /** * Specifies Create access granted. */ create = false; /** * Specifies Write access granted. */ write = false; /** * Specifies Delete access granted. */ delete = false; /** * Specifies Delete version access granted. */ deleteVersion = false; /** * Specfies Tag access granted. */ tag = false; /** * Specifies Move access granted. */ move = false; /** * Specifies Execute access granted. */ execute = false; /** * Specifies SetImmutabilityPolicy access granted. */ setImmutabilityPolicy = false; /** * Specifies that Permanent Delete is permitted. */ permanentDelete = false; /** * Converts the given permissions to a string. Using this method will guarantee the permissions are in an * order accepted by the service. * * @returns A string which represents the BlobSASPermissions */ toString() { const permissions = []; if (this.read) { permissions.push("r"); } if (this.add) { permissions.push("a"); } if (this.create) { permissions.push("c"); } if (this.write) { permissions.push("w"); } if (this.delete) { permissions.push("d"); } if (this.deleteVersion) { permissions.push("x"); } if (this.tag) { permissions.push("t"); } if (this.move) { permissions.push("m"); } if (this.execute) { permissions.push("e"); } if (this.setImmutabilityPolicy) { permissions.push("i"); } if (this.permanentDelete) { permissions.push("y"); } return permissions.join(""); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * This is a helper class to construct a string representing the permissions granted by a ServiceSAS to a container. * Setting a value to true means that any SAS which uses these permissions will grant permissions for that operation. * Once all the values are set, this should be serialized with toString and set as the permissions field on a * {@link BlobSASSignatureValues} object. It is possible to construct the permissions string without this class, but * the order of the permissions is particular and this class guarantees correctness. */ class ContainerSASPermissions { /** * Creates an {@link ContainerSASPermissions} from the specified permissions string. This method will throw an * Error if it encounters a character that does not correspond to a valid permission. * * @param permissions - */ static parse(permissions) { const containerSASPermissions = new ContainerSASPermissions(); for (const char of permissions) { switch (char) { case "r": containerSASPermissions.read = true; break; case "a": containerSASPermissions.add = true; break; case "c": containerSASPermissions.create = true; break; case "w": containerSASPermissions.write = true; break; case "d": containerSASPermissions.delete = true; break; case "l": containerSASPermissions.list = true; break; case "t": containerSASPermissions.tag = true; break; case "x": containerSASPermissions.deleteVersion = true; break; case "m": containerSASPermissions.move = true; break; case "e": containerSASPermissions.execute = true; break; case "i": containerSASPermissions.setImmutabilityPolicy = true; break; case "y": containerSASPermissions.permanentDelete = true; break; case "f": containerSASPermissions.filterByTags = true; break; default: throw new RangeError(`Invalid permission ${char}`); } } return containerSASPermissions; } /** * Creates a {@link ContainerSASPermissions} from a raw object which contains same keys as it * and boolean values for them. * * @param permissionLike - */ static from(permissionLike) { const containerSASPermissions = new ContainerSASPermissions(); if (permissionLike.read) { containerSASPermissions.read = true; } if (permissionLike.add) { containerSASPermissions.add = true; } if (permissionLike.create) { containerSASPermissions.create = true; } if (permissionLike.write) { containerSASPermissions.write = true; } if (permissionLike.delete) { containerSASPermissions.delete = true; } if (permissionLike.list) { containerSASPermissions.list = true; } if (permissionLike.deleteVersion) { containerSASPermissions.deleteVersion = true; } if (permissionLike.tag) { containerSASPermissions.tag = true; } if (permissionLike.move) { containerSASPermissions.move = true; } if (permissionLike.execute) { containerSASPermissions.execute = true; } if (permissionLike.setImmutabilityPolicy) { containerSASPermissions.setImmutabilityPolicy = true; } if (permissionLike.permanentDelete) { containerSASPermissions.permanentDelete = true; } if (permissionLike.filterByTags) { containerSASPermissions.filterByTags = true; } return containerSASPermissions; } /** * Specifies Read access granted. */ read = false; /** * Specifies Add access granted. */ add = false; /** * Specifies Create access granted. */ create = false; /** * Specifies Write access granted. */ write = false; /** * Specifies Delete access granted. */ delete = false; /** * Specifies Delete version access granted. */ deleteVersion = false; /** * Specifies List access granted. */ list = false; /** * Specfies Tag access granted. */ tag = false; /** * Specifies Move access granted. */ move = false; /** * Specifies Execute access granted. */ execute = false; /** * Specifies SetImmutabilityPolicy access granted. */ setImmutabilityPolicy = false; /** * Specifies that Permanent Delete is permitted. */ permanentDelete = false; /** * Specifies that Filter Blobs by Tags is permitted. */ filterByTags = false; /** * Converts the given permissions to a string. Using this method will guarantee the permissions are in an * order accepted by the service. * * The order of the characters should be as specified here to ensure correctness. * @see https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas * */ toString() { const permissions = []; if (this.read) { permissions.push("r"); } if (this.add) { permissions.push("a"); } if (this.create) { permissions.push("c"); } if (this.write) { permissions.push("w"); } if (this.delete) { permissions.push("d"); } if (this.deleteVersion) { permissions.push("x"); } if (this.list) { permissions.push("l"); } if (this.tag) { permissions.push("t"); } if (this.move) { permissions.push("m"); } if (this.execute) { permissions.push("e"); } if (this.setImmutabilityPolicy) { permissions.push("i"); } if (this.permanentDelete) { permissions.push("y"); } if (this.filterByTags) { permissions.push("f"); } return permissions.join(""); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Generate SasIPRange format string. For example: * * "8.8.8.8" or "1.1.1.1-255.255.255.255" * * @param ipRange - */ function ipRangeToString(ipRange) { return ipRange.end ? `${ipRange.start}-${ipRange.end}` : ipRange.start; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Protocols for generated SAS. */ var SASProtocol; (function (SASProtocol) { /** * Protocol that allows HTTPS only */ SASProtocol["Https"] = "https"; /** * Protocol that allows both HTTPS and HTTP */ SASProtocol["HttpsAndHttp"] = "https,http"; })(SASProtocol || (SASProtocol = {})); /** * Represents the components that make up an Azure Storage SAS' query parameters. This type is not constructed directly * by the user; it is only generated by the {@link AccountSASSignatureValues} and {@link BlobSASSignatureValues} * types. Once generated, it can be encoded into a {@link String} and appended to a URL directly (though caution should * be taken here in case there are existing query parameters, which might affect the appropriate means of appending * these query parameters). * * NOTE: Instances of this class are immutable. */ class SASQueryParameters { /** * The storage API version. */ version; /** * Optional. The allowed HTTP protocol(s). */ protocol; /** * Optional. The start time for this SAS token. */ startsOn; /** * Optional only when identifier is provided. The expiry time for this SAS token. */ expiresOn; /** * Optional only when identifier is provided. * Please refer to {@link AccountSASPermissions}, {@link BlobSASPermissions}, or {@link ContainerSASPermissions} for * more details. */ permissions; /** * Optional. The storage services being accessed (only for Account SAS). Please refer to {@link AccountSASServices} * for more details. */ services; /** * Optional. The storage resource types being accessed (only for Account SAS). Please refer to * {@link AccountSASResourceTypes} for more details. */ resourceTypes; /** * Optional. The signed identifier (only for {@link BlobSASSignatureValues}). * * @see https://learn.microsoft.com/rest/api/storageservices/establishing-a-stored-access-policy */ identifier; /** * Optional. Beginning in version 2025-07-05, this value specifies the Entra ID of the user would is authorized to * use the resulting SAS URL. The resulting SAS URL must be used in conjunction with an Entra ID token that has been * issued to the user specified in this value. */ delegatedUserObjectId; /** * Optional. Encryption scope to use when sending requests authorized with this SAS URI. */ encryptionScope; /** * Optional. Specifies which resources are accessible via the SAS (only for {@link BlobSASSignatureValues}). * @see https://learn.microsoft.com/rest/api/storageservices/create-service-sas#specifying-the-signed-resource-blob-service-only */ resource; /** * The signature for the SAS token. */ signature; /** * Value for cache-control header in Blob/File Service SAS. */ cacheControl; /** * Value for content-disposition header in Blob/File Service SAS. */ contentDisposition; /** * Value for content-encoding header in Blob/File Service SAS. */ contentEncoding; /** * Value for content-length header in Blob/File Service SAS. */ contentLanguage; /** * Value for content-type header in Blob/File Service SAS. */ contentType; /** * Inner value of getter ipRange. */ ipRangeInner; /** * The Azure Active Directory object ID in GUID format. * Property of user delegation key. */ signedOid; /** * The Azure Active Directory tenant ID in GUID format. * Property of user delegation key. */ signedTenantId; /** * The date-time the key is active. * Property of user delegation key. */ signedStartsOn; /** * The date-time the key expires. * Property of user delegation key. */ signedExpiresOn; /** * Abbreviation of the Azure Storage service that accepts the user delegation key. * Property of user delegation key. */ signedService; /** * The service version that created the user delegation key. * Property of user delegation key. */ signedVersion; /** * The delegated user tenant id in Azure AD. * Property of user delegation key. */ signedDelegatedUserTid; /** * Authorized AAD Object ID in GUID format. The AAD Object ID of a user authorized by the owner of the User Delegation Key * to perform the action granted by the SAS. The Azure Storage service will ensure that the owner of the user delegation key * has the required permissions before granting access but no additional permission check for the user specified in * this value will be performed. This is only used for User Delegation SAS. */ preauthorizedAgentObjectId; /** * A GUID value that will be logged in the storage diagnostic logs and can be used to correlate SAS generation with storage resource access. * This is only used for User Delegation SAS. */ correlationId; /** * Keys for request headers required in the SAS token */ requestHeaderKeys; /** * Keys for request query parameters required in the SAS token */ requestQueryParameterKeys; /** * Optional. IP range allowed for this SAS. * * @readonly */ get ipRange() { if (this.ipRangeInner) { return { end: this.ipRangeInner.end, start: this.ipRangeInner.start, }; } return undefined; } constructor(version, signature, permissionsOrOptions, services, resourceTypes, protocol, startsOn, expiresOn, ipRange, identifier, resource, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentType, userDelegationKey, preauthorizedAgentObjectId, correlationId, encryptionScope, delegatedUserObjectId, requestHeaderKeys, requestQueryParameterKeys) { this.version = version; this.signature = signature; if (permissionsOrOptions !== undefined && typeof permissionsOrOptions !== "string") { // SASQueryParametersOptions this.permissions = permissionsOrOptions.permissions; this.services = permissionsOrOptions.services; this.resourceTypes = permissionsOrOptions.resourceTypes; this.protocol = permissionsOrOptions.protocol; this.startsOn = permissionsOrOptions.startsOn; this.expiresOn = permissionsOrOptions.expiresOn; this.ipRangeInner = permissionsOrOptions.ipRange; this.identifier = permissionsOrOptions.identifier; this.delegatedUserObjectId = permissionsOrOptions.delegatedUserObjectId; this.encryptionScope = permissionsOrOptions.encryptionScope; this.resource = permissionsOrOptions.resource; this.cacheControl = permissionsOrOptions.cacheControl; this.contentDisposition = permissionsOrOptions.contentDisposition; this.contentEncoding = permissionsOrOptions.contentEncoding; this.contentLanguage = permissionsOrOptions.contentLanguage; this.contentType = permissionsOrOptions.contentType; this.requestHeaderKeys = permissionsOrOptions.requestHeaderKeys; this.requestQueryParameterKeys = permissionsOrOptions.requestQueryParameterKeys; if (permissionsOrOptions.userDelegationKey) { this.signedOid = permissionsOrOptions.userDelegationKey.signedObjectId; this.signedTenantId = permissionsOrOptions.userDelegationKey.signedTenantId; this.signedStartsOn = permissionsOrOptions.userDelegationKey.signedStartsOn; this.signedExpiresOn = permissionsOrOptions.userDelegationKey.signedExpiresOn; this.signedService = permissionsOrOptions.userDelegationKey.signedService; this.signedVersion = permissionsOrOptions.userDelegationKey.signedVersion; this.signedDelegatedUserTid = permissionsOrOptions.userDelegationKey.signedDelegatedUserTenantId; this.preauthorizedAgentObjectId = permissionsOrOptions.preauthorizedAgentObjectId; this.correlationId = permissionsOrOptions.correlationId; } } else { this.services = services; this.resourceTypes = resourceTypes; this.expiresOn = expiresOn; this.permissions = permissionsOrOptions; this.protocol = protocol; this.startsOn = startsOn; this.ipRangeInner = ipRange; this.delegatedUserObjectId = delegatedUserObjectId; this.encryptionScope = encryptionScope; this.identifier = identifier; this.resource = resource; this.cacheControl = cacheControl; this.contentDisposition = contentDisposition; this.contentEncoding = contentEncoding; this.contentLanguage = contentLanguage; this.contentType = contentType; this.requestHeaderKeys = requestHeaderKeys; this.requestQueryParameterKeys = requestQueryParameterKeys; if (userDelegationKey) { this.signedOid = userDelegationKey.signedObjectId; this.signedTenantId = userDelegationKey.signedTenantId; this.signedStartsOn = userDelegationKey.signedStartsOn; this.signedExpiresOn = userDelegationKey.signedExpiresOn; this.signedService = userDelegationKey.signedService; this.signedVersion = userDelegationKey.signedVersion; this.signedDelegatedUserTid = userDelegationKey.signedDelegatedUserTenantId; this.preauthorizedAgentObjectId = preauthorizedAgentObjectId; this.correlationId = correlationId; } } } /** * Encodes all SAS query parameters into a string that can be appended to a URL. * */ toString() { const params = [ "sv", "ss", "srt", "spr", "st", "se", "sip", "si", "ses", "skoid", // Signed object ID "sktid", // Signed tenant ID "skt", // Signed key start time "ske", // Signed key expiry time "sks", // Signed key service "skv", // Signed key version "sr", "sp", "rscc", "rscd", "rsce", "rscl", "rsct", "saoid", "scid", "sduoid", // Signed key user delegation object ID "skdutid", // Signed key user delegation tenant ID "srh", // Request Headers "srq", // Request QueryParameters "sig", ]; const queries = []; for (const param of params) { switch (param) { case "sv": this.tryAppendQueryParameter(queries, param, this.version); break; case "ss": this.tryAppendQueryParameter(queries, param, this.services); break; case "srt": this.tryAppendQueryParameter(queries, param, this.resourceTypes); break; case "spr": this.tryAppendQueryParameter(queries, param, this.protocol); break; case "st": this.tryAppendQueryParameter(queries, param, this.startsOn ? truncatedISO8061Date(this.startsOn, false) : undefined); break; case "se": this.tryAppendQueryParameter(queries, param, this.expiresOn ? truncatedISO8061Date(this.expiresOn, false) : undefined); break; case "sip": this.tryAppendQueryParameter(queries, param, this.ipRange ? ipRangeToString(this.ipRange) : undefined); break; case "si": this.tryAppendQueryParameter(queries, param, this.identifier); break; case "ses": this.tryAppendQueryParameter(queries, param, this.encryptionScope); break; case "skoid": // Signed object ID this.tryAppendQueryParameter(queries, param, this.signedOid); break; case "sktid": // Signed tenant ID this.tryAppendQueryParameter(queries, param, this.signedTenantId); break; case "skt": // Signed key start time this.tryAppendQueryParameter(queries, param, this.signedStartsOn ? truncatedISO8061Date(this.signedStartsOn, false) : undefined); break; case "ske": // Signed key expiry time this.tryAppendQueryParameter(queries, param, this.signedExpiresOn ? truncatedISO8061Date(this.signedExpiresOn, false) : undefined); break; case "sks": // Signed key service this.tryAppendQueryParameter(queries, param, this.signedService); break; case "skv": // Signed key version this.tryAppendQueryParameter(queries, param, this.signedVersion); break; case "skdutid": this.tryAppendQueryParameter(queries, param, this.signedDelegatedUserTid); break; case "sr": this.tryAppendQueryParameter(queries, param, this.resource); break; case "sp": this.tryAppendQueryParameter(queries, param, this.permissions); break; case "sig": this.tryAppendQueryParameter(queries, param, this.signature); break; case "rscc": this.tryAppendQueryParameter(queries, param, this.cacheControl); break; case "rscd": this.tryAppendQueryParameter(queries, param, this.contentDisposition); break; case "rsce": this.tryAppendQueryParameter(queries, param, this.contentEncoding); break; case "rscl": this.tryAppendQueryParameter(queries, param, this.contentLanguage); break; case "rsct": this.tryAppendQueryParameter(queries, param, this.contentType); break; case "saoid": this.tryAppendQueryParameter(queries, param, this.preauthorizedAgentObjectId); break; case "scid": this.tryAppendQueryParameter(queries, param, this.correlationId); break; case "sduoid": this.tryAppendQueryParameter(queries, param, this.delegatedUserObjectId); break; case "srh": // Request headers this.tryAppendQueryParameter(queries, param, this.requestHeaderKeys); break; case "srq": // Request headers this.tryAppendQueryParameter(queries, param, this.requestQueryParameterKeys); break; } } return queries.join("&"); } /** * A private helper method used to filter and append query key/value pairs into an array. * * @param queries - * @param key - * @param value - */ tryAppendQueryParameter(queries, key, value) { if (!value) { return; } key = encodeURIComponent(key); value = encodeURIComponent(value); if (key.length > 0 && value.length > 0) { queries.push(`${key}=${value}`); } } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function generateBlobSASQueryParameters(blobSASSignatureValues, sharedKeyCredentialOrUserDelegationKey, accountName) { return generateBlobSASQueryParametersInternal(blobSASSignatureValues, sharedKeyCredentialOrUserDelegationKey, accountName).sasQueryParameters; } function generateBlobSASQueryParametersInternal(blobSASSignatureValues, sharedKeyCredentialOrUserDelegationKey, accountName) { const version = blobSASSignatureValues.version ? blobSASSignatureValues.version : SERVICE_VERSION; const sharedKeyCredential = sharedKeyCredentialOrUserDelegationKey instanceof StorageSharedKeyCredential ? sharedKeyCredentialOrUserDelegationKey : undefined; let userDelegationKeyCredential; if (sharedKeyCredential === undefined && accountName !== undefined) { userDelegationKeyCredential = new UserDelegationKeyCredential(accountName, sharedKeyCredentialOrUserDelegationKey); } if (sharedKeyCredential === undefined && userDelegationKeyCredential === undefined) { throw TypeError("Invalid sharedKeyCredential, userDelegationKey or accountName."); } // Version 2020-12-06 adds support for encryptionscope in SAS. if (version >= "2020-12-06") { if (sharedKeyCredential !== undefined) { return generateBlobSASQueryParameters20201206(blobSASSignatureValues, sharedKeyCredential); } else { if (version >= "2026-04-06") { return generateBlobSASQueryParametersUDK20260406(blobSASSignatureValues, userDelegationKeyCredential); } else if (version >= "2025-07-05") { return generateBlobSASQueryParametersUDK20250705(blobSASSignatureValues, userDelegationKeyCredential); } else { return generateBlobSASQueryParametersUDK20201206(blobSASSignatureValues, userDelegationKeyCredential); } } } // Version 2019-12-12 adds support for the blob tags permission. // Version 2018-11-09 adds support for the signed resource and signed blob snapshot time fields. // https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas#constructing-the-signature-string if (version >= "2018-11-09") { if (sharedKeyCredential !== undefined) { return generateBlobSASQueryParameters20181109(blobSASSignatureValues, sharedKeyCredential); } else { // Version 2020-02-10 delegation SAS signature construction includes preauthorizedAgentObjectId, agentObjectId, correlationId. if (version >= "2020-02-10") { return generateBlobSASQueryParametersUDK20200210(blobSASSignatureValues, userDelegationKeyCredential); } else { return generateBlobSASQueryParametersUDK20181109(blobSASSignatureValues, userDelegationKeyCredential); } } } if (version >= "2015-04-05") { if (sharedKeyCredential !== undefined) { return generateBlobSASQueryParameters20150405(blobSASSignatureValues, sharedKeyCredential); } else { throw new RangeError("'version' must be >= '2018-11-09' when generating user delegation SAS using user delegation key."); } } throw new RangeError("'version' must be >= '2015-04-05'."); } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * IMPLEMENTATION FOR API VERSION FROM 2015-04-05 AND BEFORE 2018-11-09. * * Creates an instance of SASQueryParameters. * * Only accepts required settings needed to create a SAS. For optional settings please * set corresponding properties directly, such as permissions, startsOn and identifier. * * WARNING: When identifier is not provided, permissions and expiresOn are required. * You MUST assign value to identifier or expiresOn & permissions manually if you initial with * this constructor. * * @param blobSASSignatureValues - * @param sharedKeyCredential - */ function generateBlobSASQueryParameters20150405(blobSASSignatureValues, sharedKeyCredential) { blobSASSignatureValues = SASSignatureValuesSanityCheckAndAutofill(blobSASSignatureValues); if (!blobSASSignatureValues.identifier && !(blobSASSignatureValues.permissions && blobSASSignatureValues.expiresOn)) { throw new RangeError("Must provide 'permissions' and 'expiresOn' for Blob SAS generation when 'identifier' is not provided."); } let resource = "c"; if (blobSASSignatureValues.blobName) { resource = "b"; } // Calling parse and toString guarantees the proper ordering and throws on invalid characters. let verifiedPermissions; if (blobSASSignatureValues.permissions) { if (blobSASSignatureValues.blobName) { verifiedPermissions = BlobSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } else { verifiedPermissions = ContainerSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } } // Signature is generated on the un-url-encoded values. const stringToSign = [ verifiedPermissions ? verifiedPermissions : "", blobSASSignatureValues.startsOn ? truncatedISO8061Date(blobSASSignatureValues.startsOn, false) : "", blobSASSignatureValues.expiresOn ? truncatedISO8061Date(blobSASSignatureValues.expiresOn, false) : "", getCanonicalName(sharedKeyCredential.accountName, blobSASSignatureValues.containerName, blobSASSignatureValues.blobName), blobSASSignatureValues.identifier, blobSASSignatureValues.ipRange ? ipRangeToString(blobSASSignatureValues.ipRange) : "", blobSASSignatureValues.protocol ? blobSASSignatureValues.protocol : "", blobSASSignatureValues.version, blobSASSignatureValues.cacheControl ? blobSASSignatureValues.cacheControl : "", blobSASSignatureValues.contentDisposition ? blobSASSignatureValues.contentDisposition : "", blobSASSignatureValues.contentEncoding ? blobSASSignatureValues.contentEncoding : "", blobSASSignatureValues.contentLanguage ? blobSASSignatureValues.contentLanguage : "", blobSASSignatureValues.contentType ? blobSASSignatureValues.contentType : "", ].join("\n"); const signature = sharedKeyCredential.computeHMACSHA256(stringToSign); return { sasQueryParameters: new SASQueryParameters(blobSASSignatureValues.version, signature, verifiedPermissions, undefined, undefined, blobSASSignatureValues.protocol, blobSASSignatureValues.startsOn, blobSASSignatureValues.expiresOn, blobSASSignatureValues.ipRange, blobSASSignatureValues.identifier, resource, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType), stringToSign: stringToSign, }; } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * IMPLEMENTATION FOR API VERSION FROM 2018-11-09. * * Creates an instance of SASQueryParameters. * * Only accepts required settings needed to create a SAS. For optional settings please * set corresponding properties directly, such as permissions, startsOn and identifier. * * WARNING: When identifier is not provided, permissions and expiresOn are required. * You MUST assign value to identifier or expiresOn & permissions manually if you initial with * this constructor. * * @param blobSASSignatureValues - * @param sharedKeyCredential - */ function generateBlobSASQueryParameters20181109(blobSASSignatureValues, sharedKeyCredential) { blobSASSignatureValues = SASSignatureValuesSanityCheckAndAutofill(blobSASSignatureValues); if (!blobSASSignatureValues.identifier && !(blobSASSignatureValues.permissions && blobSASSignatureValues.expiresOn)) { throw new RangeError("Must provide 'permissions' and 'expiresOn' for Blob SAS generation when 'identifier' is not provided."); } let resource = "c"; let timestamp = blobSASSignatureValues.snapshotTime; if (blobSASSignatureValues.blobName) { resource = "b"; if (blobSASSignatureValues.snapshotTime) { resource = "bs"; } else if (blobSASSignatureValues.versionId) { resource = "bv"; timestamp = blobSASSignatureValues.versionId; } } // Calling parse and toString guarantees the proper ordering and throws on invalid characters. let verifiedPermissions; if (blobSASSignatureValues.permissions) { if (blobSASSignatureValues.blobName) { verifiedPermissions = BlobSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } else { verifiedPermissions = ContainerSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } } // Signature is generated on the un-url-encoded values. const stringToSign = [ verifiedPermissions ? verifiedPermissions : "", blobSASSignatureValues.startsOn ? truncatedISO8061Date(blobSASSignatureValues.startsOn, false) : "", blobSASSignatureValues.expiresOn ? truncatedISO8061Date(blobSASSignatureValues.expiresOn, false) : "", getCanonicalName(sharedKeyCredential.accountName, blobSASSignatureValues.containerName, blobSASSignatureValues.blobName), blobSASSignatureValues.identifier, blobSASSignatureValues.ipRange ? ipRangeToString(blobSASSignatureValues.ipRange) : "", blobSASSignatureValues.protocol ? blobSASSignatureValues.protocol : "", blobSASSignatureValues.version, resource, timestamp, blobSASSignatureValues.cacheControl ? blobSASSignatureValues.cacheControl : "", blobSASSignatureValues.contentDisposition ? blobSASSignatureValues.contentDisposition : "", blobSASSignatureValues.contentEncoding ? blobSASSignatureValues.contentEncoding : "", blobSASSignatureValues.contentLanguage ? blobSASSignatureValues.contentLanguage : "", blobSASSignatureValues.contentType ? blobSASSignatureValues.contentType : "", ].join("\n"); const signature = sharedKeyCredential.computeHMACSHA256(stringToSign); return { sasQueryParameters: new SASQueryParameters(blobSASSignatureValues.version, signature, verifiedPermissions, undefined, undefined, blobSASSignatureValues.protocol, blobSASSignatureValues.startsOn, blobSASSignatureValues.expiresOn, blobSASSignatureValues.ipRange, blobSASSignatureValues.identifier, resource, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType), stringToSign: stringToSign, }; } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * IMPLEMENTATION FOR API VERSION FROM 2020-12-06. * * Creates an instance of SASQueryParameters. * * Only accepts required settings needed to create a SAS. For optional settings please * set corresponding properties directly, such as permissions, startsOn and identifier. * * WARNING: When identifier is not provided, permissions and expiresOn are required. * You MUST assign value to identifier or expiresOn & permissions manually if you initial with * this constructor. * * @param blobSASSignatureValues - * @param sharedKeyCredential - */ function generateBlobSASQueryParameters20201206(blobSASSignatureValues, sharedKeyCredential) { blobSASSignatureValues = SASSignatureValuesSanityCheckAndAutofill(blobSASSignatureValues); if (!blobSASSignatureValues.identifier && !(blobSASSignatureValues.permissions && blobSASSignatureValues.expiresOn)) { throw new RangeError("Must provide 'permissions' and 'expiresOn' for Blob SAS generation when 'identifier' is not provided."); } let resource = "c"; let timestamp = blobSASSignatureValues.snapshotTime; if (blobSASSignatureValues.blobName) { resource = "b"; if (blobSASSignatureValues.snapshotTime) { resource = "bs"; } else if (blobSASSignatureValues.versionId) { resource = "bv"; timestamp = blobSASSignatureValues.versionId; } } // Calling parse and toString guarantees the proper ordering and throws on invalid characters. let verifiedPermissions; if (blobSASSignatureValues.permissions) { if (blobSASSignatureValues.blobName) { verifiedPermissions = BlobSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } else { verifiedPermissions = ContainerSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } } // Signature is generated on the un-url-encoded values. const stringToSign = [ verifiedPermissions ? verifiedPermissions : "", blobSASSignatureValues.startsOn ? truncatedISO8061Date(blobSASSignatureValues.startsOn, false) : "", blobSASSignatureValues.expiresOn ? truncatedISO8061Date(blobSASSignatureValues.expiresOn, false) : "", getCanonicalName(sharedKeyCredential.accountName, blobSASSignatureValues.containerName, blobSASSignatureValues.blobName), blobSASSignatureValues.identifier, blobSASSignatureValues.ipRange ? ipRangeToString(blobSASSignatureValues.ipRange) : "", blobSASSignatureValues.protocol ? blobSASSignatureValues.protocol : "", blobSASSignatureValues.version, resource, timestamp, blobSASSignatureValues.encryptionScope, blobSASSignatureValues.cacheControl ? blobSASSignatureValues.cacheControl : "", blobSASSignatureValues.contentDisposition ? blobSASSignatureValues.contentDisposition : "", blobSASSignatureValues.contentEncoding ? blobSASSignatureValues.contentEncoding : "", blobSASSignatureValues.contentLanguage ? blobSASSignatureValues.contentLanguage : "", blobSASSignatureValues.contentType ? blobSASSignatureValues.contentType : "", ].join("\n"); const signature = sharedKeyCredential.computeHMACSHA256(stringToSign); return { sasQueryParameters: new SASQueryParameters(blobSASSignatureValues.version, signature, verifiedPermissions, undefined, undefined, blobSASSignatureValues.protocol, blobSASSignatureValues.startsOn, blobSASSignatureValues.expiresOn, blobSASSignatureValues.ipRange, blobSASSignatureValues.identifier, resource, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, undefined, undefined, undefined, blobSASSignatureValues.encryptionScope), stringToSign: stringToSign, }; } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * IMPLEMENTATION FOR API VERSION FROM 2018-11-09. * * Creates an instance of SASQueryParameters. * * Only accepts required settings needed to create a SAS. For optional settings please * set corresponding properties directly, such as permissions, startsOn. * * WARNING: identifier will be ignored, permissions and expiresOn are required. * * @param blobSASSignatureValues - * @param userDelegationKeyCredential - */ function generateBlobSASQueryParametersUDK20181109(blobSASSignatureValues, userDelegationKeyCredential) { blobSASSignatureValues = SASSignatureValuesSanityCheckAndAutofill(blobSASSignatureValues); // Stored access policies are not supported for a user delegation SAS. if (!blobSASSignatureValues.permissions || !blobSASSignatureValues.expiresOn) { throw new RangeError("Must provide 'permissions' and 'expiresOn' for Blob SAS generation when generating user delegation SAS."); } let resource = "c"; let timestamp = blobSASSignatureValues.snapshotTime; if (blobSASSignatureValues.blobName) { resource = "b"; if (blobSASSignatureValues.snapshotTime) { resource = "bs"; } else if (blobSASSignatureValues.versionId) { resource = "bv"; timestamp = blobSASSignatureValues.versionId; } } // Calling parse and toString guarantees the proper ordering and throws on invalid characters. let verifiedPermissions; if (blobSASSignatureValues.permissions) { if (blobSASSignatureValues.blobName) { verifiedPermissions = BlobSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } else { verifiedPermissions = ContainerSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } } // Signature is generated on the un-url-encoded values. const stringToSign = [ verifiedPermissions ? verifiedPermissions : "", blobSASSignatureValues.startsOn ? truncatedISO8061Date(blobSASSignatureValues.startsOn, false) : "", blobSASSignatureValues.expiresOn ? truncatedISO8061Date(blobSASSignatureValues.expiresOn, false) : "", getCanonicalName(userDelegationKeyCredential.accountName, blobSASSignatureValues.containerName, blobSASSignatureValues.blobName), userDelegationKeyCredential.userDelegationKey.signedObjectId, userDelegationKeyCredential.userDelegationKey.signedTenantId, userDelegationKeyCredential.userDelegationKey.signedStartsOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedStartsOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedExpiresOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedExpiresOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedService, userDelegationKeyCredential.userDelegationKey.signedVersion, blobSASSignatureValues.ipRange ? ipRangeToString(blobSASSignatureValues.ipRange) : "", blobSASSignatureValues.protocol ? blobSASSignatureValues.protocol : "", blobSASSignatureValues.version, resource, timestamp, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, ].join("\n"); const signature = userDelegationKeyCredential.computeHMACSHA256(stringToSign); return { sasQueryParameters: new SASQueryParameters(blobSASSignatureValues.version, signature, verifiedPermissions, undefined, undefined, blobSASSignatureValues.protocol, blobSASSignatureValues.startsOn, blobSASSignatureValues.expiresOn, blobSASSignatureValues.ipRange, blobSASSignatureValues.identifier, resource, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, userDelegationKeyCredential.userDelegationKey), stringToSign: stringToSign, }; } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * IMPLEMENTATION FOR API VERSION FROM 2020-02-10. * * Creates an instance of SASQueryParameters. * * Only accepts required settings needed to create a SAS. For optional settings please * set corresponding properties directly, such as permissions, startsOn. * * WARNING: identifier will be ignored, permissions and expiresOn are required. * * @param blobSASSignatureValues - * @param userDelegationKeyCredential - */ function generateBlobSASQueryParametersUDK20200210(blobSASSignatureValues, userDelegationKeyCredential) { blobSASSignatureValues = SASSignatureValuesSanityCheckAndAutofill(blobSASSignatureValues); // Stored access policies are not supported for a user delegation SAS. if (!blobSASSignatureValues.permissions || !blobSASSignatureValues.expiresOn) { throw new RangeError("Must provide 'permissions' and 'expiresOn' for Blob SAS generation when generating user delegation SAS."); } let resource = "c"; let timestamp = blobSASSignatureValues.snapshotTime; if (blobSASSignatureValues.blobName) { resource = "b"; if (blobSASSignatureValues.snapshotTime) { resource = "bs"; } else if (blobSASSignatureValues.versionId) { resource = "bv"; timestamp = blobSASSignatureValues.versionId; } } // Calling parse and toString guarantees the proper ordering and throws on invalid characters. let verifiedPermissions; if (blobSASSignatureValues.permissions) { if (blobSASSignatureValues.blobName) { verifiedPermissions = BlobSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } else { verifiedPermissions = ContainerSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } } // Signature is generated on the un-url-encoded values. const stringToSign = [ verifiedPermissions ? verifiedPermissions : "", blobSASSignatureValues.startsOn ? truncatedISO8061Date(blobSASSignatureValues.startsOn, false) : "", blobSASSignatureValues.expiresOn ? truncatedISO8061Date(blobSASSignatureValues.expiresOn, false) : "", getCanonicalName(userDelegationKeyCredential.accountName, blobSASSignatureValues.containerName, blobSASSignatureValues.blobName), userDelegationKeyCredential.userDelegationKey.signedObjectId, userDelegationKeyCredential.userDelegationKey.signedTenantId, userDelegationKeyCredential.userDelegationKey.signedStartsOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedStartsOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedExpiresOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedExpiresOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedService, userDelegationKeyCredential.userDelegationKey.signedVersion, blobSASSignatureValues.preauthorizedAgentObjectId, undefined, // agentObjectId blobSASSignatureValues.correlationId, blobSASSignatureValues.ipRange ? ipRangeToString(blobSASSignatureValues.ipRange) : "", blobSASSignatureValues.protocol ? blobSASSignatureValues.protocol : "", blobSASSignatureValues.version, resource, timestamp, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, ].join("\n"); const signature = userDelegationKeyCredential.computeHMACSHA256(stringToSign); return { sasQueryParameters: new SASQueryParameters(blobSASSignatureValues.version, signature, verifiedPermissions, undefined, undefined, blobSASSignatureValues.protocol, blobSASSignatureValues.startsOn, blobSASSignatureValues.expiresOn, blobSASSignatureValues.ipRange, blobSASSignatureValues.identifier, resource, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, userDelegationKeyCredential.userDelegationKey, blobSASSignatureValues.preauthorizedAgentObjectId, blobSASSignatureValues.correlationId), stringToSign: stringToSign, }; } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * IMPLEMENTATION FOR API VERSION FROM 2020-12-06. * * Creates an instance of SASQueryParameters. * * Only accepts required settings needed to create a SAS. For optional settings please * set corresponding properties directly, such as permissions, startsOn. * * WARNING: identifier will be ignored, permissions and expiresOn are required. * * @param blobSASSignatureValues - * @param userDelegationKeyCredential - */ function generateBlobSASQueryParametersUDK20201206(blobSASSignatureValues, userDelegationKeyCredential) { blobSASSignatureValues = SASSignatureValuesSanityCheckAndAutofill(blobSASSignatureValues); // Stored access policies are not supported for a user delegation SAS. if (!blobSASSignatureValues.permissions || !blobSASSignatureValues.expiresOn) { throw new RangeError("Must provide 'permissions' and 'expiresOn' for Blob SAS generation when generating user delegation SAS."); } let resource = "c"; let timestamp = blobSASSignatureValues.snapshotTime; if (blobSASSignatureValues.blobName) { resource = "b"; if (blobSASSignatureValues.snapshotTime) { resource = "bs"; } else if (blobSASSignatureValues.versionId) { resource = "bv"; timestamp = blobSASSignatureValues.versionId; } } // Calling parse and toString guarantees the proper ordering and throws on invalid characters. let verifiedPermissions; if (blobSASSignatureValues.permissions) { if (blobSASSignatureValues.blobName) { verifiedPermissions = BlobSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } else { verifiedPermissions = ContainerSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } } // Signature is generated on the un-url-encoded values. const stringToSign = [ verifiedPermissions ? verifiedPermissions : "", blobSASSignatureValues.startsOn ? truncatedISO8061Date(blobSASSignatureValues.startsOn, false) : "", blobSASSignatureValues.expiresOn ? truncatedISO8061Date(blobSASSignatureValues.expiresOn, false) : "", getCanonicalName(userDelegationKeyCredential.accountName, blobSASSignatureValues.containerName, blobSASSignatureValues.blobName), userDelegationKeyCredential.userDelegationKey.signedObjectId, userDelegationKeyCredential.userDelegationKey.signedTenantId, userDelegationKeyCredential.userDelegationKey.signedStartsOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedStartsOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedExpiresOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedExpiresOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedService, userDelegationKeyCredential.userDelegationKey.signedVersion, blobSASSignatureValues.preauthorizedAgentObjectId, undefined, // agentObjectId blobSASSignatureValues.correlationId, blobSASSignatureValues.ipRange ? ipRangeToString(blobSASSignatureValues.ipRange) : "", blobSASSignatureValues.protocol ? blobSASSignatureValues.protocol : "", blobSASSignatureValues.version, resource, timestamp, blobSASSignatureValues.encryptionScope, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, ].join("\n"); const signature = userDelegationKeyCredential.computeHMACSHA256(stringToSign); return { sasQueryParameters: new SASQueryParameters(blobSASSignatureValues.version, signature, verifiedPermissions, undefined, undefined, blobSASSignatureValues.protocol, blobSASSignatureValues.startsOn, blobSASSignatureValues.expiresOn, blobSASSignatureValues.ipRange, blobSASSignatureValues.identifier, resource, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, userDelegationKeyCredential.userDelegationKey, blobSASSignatureValues.preauthorizedAgentObjectId, blobSASSignatureValues.correlationId, blobSASSignatureValues.encryptionScope), stringToSign: stringToSign, }; } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * IMPLEMENTATION FOR API VERSION FROM 2020-12-06. * * Creates an instance of SASQueryParameters. * * Only accepts required settings needed to create a SAS. For optional settings please * set corresponding properties directly, such as permissions, startsOn. * * WARNING: identifier will be ignored, permissions and expiresOn are required. * * @param blobSASSignatureValues - * @param userDelegationKeyCredential - */ function generateBlobSASQueryParametersUDK20250705(blobSASSignatureValues, userDelegationKeyCredential) { blobSASSignatureValues = SASSignatureValuesSanityCheckAndAutofill(blobSASSignatureValues); // Stored access policies are not supported for a user delegation SAS. if (!blobSASSignatureValues.permissions || !blobSASSignatureValues.expiresOn) { throw new RangeError("Must provide 'permissions' and 'expiresOn' for Blob SAS generation when generating user delegation SAS."); } let resource = "c"; let timestamp = blobSASSignatureValues.snapshotTime; if (blobSASSignatureValues.blobName) { resource = "b"; if (blobSASSignatureValues.snapshotTime) { resource = "bs"; } else if (blobSASSignatureValues.versionId) { resource = "bv"; timestamp = blobSASSignatureValues.versionId; } } // Calling parse and toString guarantees the proper ordering and throws on invalid characters. let verifiedPermissions; if (blobSASSignatureValues.permissions) { if (blobSASSignatureValues.blobName) { verifiedPermissions = BlobSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } else { verifiedPermissions = ContainerSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } } // Signature is generated on the un-url-encoded values. const stringToSign = [ verifiedPermissions ? verifiedPermissions : "", blobSASSignatureValues.startsOn ? truncatedISO8061Date(blobSASSignatureValues.startsOn, false) : "", blobSASSignatureValues.expiresOn ? truncatedISO8061Date(blobSASSignatureValues.expiresOn, false) : "", getCanonicalName(userDelegationKeyCredential.accountName, blobSASSignatureValues.containerName, blobSASSignatureValues.blobName), userDelegationKeyCredential.userDelegationKey.signedObjectId, userDelegationKeyCredential.userDelegationKey.signedTenantId, userDelegationKeyCredential.userDelegationKey.signedStartsOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedStartsOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedExpiresOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedExpiresOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedService, userDelegationKeyCredential.userDelegationKey.signedVersion, blobSASSignatureValues.preauthorizedAgentObjectId, undefined, // agentObjectId blobSASSignatureValues.correlationId, userDelegationKeyCredential.userDelegationKey.signedDelegatedUserTenantId, // SignedKeyDelegatedUserTenantId, will be added in a future release. blobSASSignatureValues.delegatedUserObjectId, blobSASSignatureValues.ipRange ? ipRangeToString(blobSASSignatureValues.ipRange) : "", blobSASSignatureValues.protocol ? blobSASSignatureValues.protocol : "", blobSASSignatureValues.version, resource, timestamp, blobSASSignatureValues.encryptionScope, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, ].join("\n"); const signature = userDelegationKeyCredential.computeHMACSHA256(stringToSign); return { sasQueryParameters: new SASQueryParameters(blobSASSignatureValues.version, signature, verifiedPermissions, undefined, undefined, blobSASSignatureValues.protocol, blobSASSignatureValues.startsOn, blobSASSignatureValues.expiresOn, blobSASSignatureValues.ipRange, blobSASSignatureValues.identifier, resource, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, userDelegationKeyCredential.userDelegationKey, blobSASSignatureValues.preauthorizedAgentObjectId, blobSASSignatureValues.correlationId, blobSASSignatureValues.encryptionScope, blobSASSignatureValues.delegatedUserObjectId), stringToSign: stringToSign, }; } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * IMPLEMENTATION FOR API VERSION FROM 2020-12-06. * * Creates an instance of SASQueryParameters. * * Only accepts required settings needed to create a SAS. For optional settings please * set corresponding properties directly, such as permissions, startsOn. * * WARNING: identifier will be ignored, permissions and expiresOn are required. * * @param blobSASSignatureValues - * @param userDelegationKeyCredential - */ function generateBlobSASQueryParametersUDK20260406(blobSASSignatureValues, userDelegationKeyCredential) { blobSASSignatureValues = SASSignatureValuesSanityCheckAndAutofill(blobSASSignatureValues); // Stored access policies are not supported for a user delegation SAS. if (!blobSASSignatureValues.permissions || !blobSASSignatureValues.expiresOn) { throw new RangeError("Must provide 'permissions' and 'expiresOn' for Blob SAS generation when generating user delegation SAS."); } let resource = "c"; let timestamp = blobSASSignatureValues.snapshotTime; if (blobSASSignatureValues.blobName) { resource = "b"; if (blobSASSignatureValues.snapshotTime) { resource = "bs"; } else if (blobSASSignatureValues.versionId) { resource = "bv"; timestamp = blobSASSignatureValues.versionId; } } // Calling parse and toString guarantees the proper ordering and throws on invalid characters. let verifiedPermissions; if (blobSASSignatureValues.permissions) { if (blobSASSignatureValues.blobName) { verifiedPermissions = BlobSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } else { verifiedPermissions = ContainerSASPermissions.parse(blobSASSignatureValues.permissions.toString()).toString(); } } // Signature is generated on the un-url-encoded values. const stringToSign = [ verifiedPermissions ? verifiedPermissions : "", blobSASSignatureValues.startsOn ? truncatedISO8061Date(blobSASSignatureValues.startsOn, false) : "", blobSASSignatureValues.expiresOn ? truncatedISO8061Date(blobSASSignatureValues.expiresOn, false) : "", getCanonicalName(userDelegationKeyCredential.accountName, blobSASSignatureValues.containerName, blobSASSignatureValues.blobName), userDelegationKeyCredential.userDelegationKey.signedObjectId, userDelegationKeyCredential.userDelegationKey.signedTenantId, userDelegationKeyCredential.userDelegationKey.signedStartsOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedStartsOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedExpiresOn ? truncatedISO8061Date(userDelegationKeyCredential.userDelegationKey.signedExpiresOn, false) : "", userDelegationKeyCredential.userDelegationKey.signedService, userDelegationKeyCredential.userDelegationKey.signedVersion, blobSASSignatureValues.preauthorizedAgentObjectId, undefined, // agentObjectId blobSASSignatureValues.correlationId, userDelegationKeyCredential.userDelegationKey.signedDelegatedUserTenantId, // SignedKeyDelegatedUserTenantId, will be added in a future release. blobSASSignatureValues.delegatedUserObjectId, blobSASSignatureValues.ipRange ? ipRangeToString(blobSASSignatureValues.ipRange) : "", blobSASSignatureValues.protocol ? blobSASSignatureValues.protocol : "", blobSASSignatureValues.version, resource, timestamp, blobSASSignatureValues.encryptionScope, formatRequestHeadersForSasSigning(blobSASSignatureValues.requestHeaders), formatRequestQueryParametersForSasSigning(blobSASSignatureValues.requestQueryParameters), blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, ].join("\n"); const signature = userDelegationKeyCredential.computeHMACSHA256(stringToSign); return { sasQueryParameters: new SASQueryParameters(blobSASSignatureValues.version, signature, verifiedPermissions, undefined, undefined, blobSASSignatureValues.protocol, blobSASSignatureValues.startsOn, blobSASSignatureValues.expiresOn, blobSASSignatureValues.ipRange, blobSASSignatureValues.identifier, resource, blobSASSignatureValues.cacheControl, blobSASSignatureValues.contentDisposition, blobSASSignatureValues.contentEncoding, blobSASSignatureValues.contentLanguage, blobSASSignatureValues.contentType, userDelegationKeyCredential.userDelegationKey, blobSASSignatureValues.preauthorizedAgentObjectId, blobSASSignatureValues.correlationId, blobSASSignatureValues.encryptionScope, blobSASSignatureValues.delegatedUserObjectId, getKeysOfRequestHeaders(blobSASSignatureValues.requestHeaders), getKeysOfRequestHeaders(blobSASSignatureValues.requestQueryParameters)), stringToSign: stringToSign, }; } function formatRequestHeadersForSasSigning(requestHeaders) { if (requestHeaders === undefined) { return undefined; } let canonicalValue = ""; Object.keys(requestHeaders).forEach(function (key) { // key: the name of the object key // index: the ordinal position of the key within the object canonicalValue = canonicalValue + key + ":" + requestHeaders[key] + "\n"; }); return canonicalValue; } function formatRequestQueryParametersForSasSigning(queryParameters) { if (queryParameters === undefined) { return undefined; } let canonicalValue = ""; Object.keys(queryParameters).forEach(function (key) { // key: the name of the object key // index: the ordinal position of the key within the object canonicalValue = canonicalValue + "\n" + key + ":" + queryParameters[key]; }); return canonicalValue; } function getKeysOfRequestHeaders(requestHeaders) { if (requestHeaders === undefined) { return undefined; } let requestKeys = ""; let index = 0; Object.keys(requestHeaders).forEach(function (key) { // key: the name of the object key // index: the ordinal position of the key within the object if (index !== 0) { requestKeys = requestKeys + ","; } requestKeys = requestKeys + key; ++index; }); return requestKeys; } function getCanonicalName(accountName, containerName, blobName) { // Container: "/blob/account/containerName" // Blob: "/blob/account/containerName/blobName" const elements = [`/blob/${accountName}/${containerName}`]; if (blobName) { elements.push(`/${blobName}`); } return elements.join(""); } function SASSignatureValuesSanityCheckAndAutofill(blobSASSignatureValues) { const version = blobSASSignatureValues.version ? blobSASSignatureValues.version : SERVICE_VERSION; if (blobSASSignatureValues.snapshotTime && version < "2018-11-09") { throw RangeError("'version' must be >= '2018-11-09' when providing 'snapshotTime'."); } if (blobSASSignatureValues.blobName === undefined && blobSASSignatureValues.snapshotTime) { throw RangeError("Must provide 'blobName' when providing 'snapshotTime'."); } if (blobSASSignatureValues.versionId && version < "2019-10-10") { throw RangeError("'version' must be >= '2019-10-10' when providing 'versionId'."); } if (blobSASSignatureValues.blobName === undefined && blobSASSignatureValues.versionId) { throw RangeError("Must provide 'blobName' when providing 'versionId'."); } if (blobSASSignatureValues.permissions && blobSASSignatureValues.permissions.setImmutabilityPolicy && version < "2020-08-04") { throw RangeError("'version' must be >= '2020-08-04' when provided 'i' permission."); } if (blobSASSignatureValues.permissions && blobSASSignatureValues.permissions.deleteVersion && version < "2019-10-10") { throw RangeError("'version' must be >= '2019-10-10' when providing 'x' permission."); } if (blobSASSignatureValues.permissions && blobSASSignatureValues.permissions.permanentDelete && version < "2019-10-10") { throw RangeError("'version' must be >= '2019-10-10' when providing 'y' permission."); } if (blobSASSignatureValues.permissions && blobSASSignatureValues.permissions.tag && version < "2019-12-12") { throw RangeError("'version' must be >= '2019-12-12' when providing 't' permission."); } if (version < "2020-02-10" && blobSASSignatureValues.permissions && (blobSASSignatureValues.permissions.move || blobSASSignatureValues.permissions.execute)) { throw RangeError("'version' must be >= '2020-02-10' when providing the 'm' or 'e' permission."); } if (version < "2021-04-10" && blobSASSignatureValues.permissions && blobSASSignatureValues.permissions.filterByTags) { throw RangeError("'version' must be >= '2021-04-10' when providing the 'f' permission."); } if (version < "2020-02-10" && (blobSASSignatureValues.preauthorizedAgentObjectId || blobSASSignatureValues.correlationId)) { throw RangeError("'version' must be >= '2020-02-10' when providing 'preauthorizedAgentObjectId' or 'correlationId'."); } if (blobSASSignatureValues.encryptionScope && version < "2020-12-06") { throw RangeError("'version' must be >= '2020-12-06' when provided 'encryptionScope' in SAS."); } blobSASSignatureValues.version = version; return blobSASSignatureValues; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A client that manages leases for a {@link ContainerClient} or a {@link BlobClient}. */ class BlobLeaseClient { _leaseId; _url; _containerOrBlobOperation; _isContainer; /** * Gets the lease Id. * * @readonly */ get leaseId() { return this._leaseId; } /** * Gets the url. * * @readonly */ get url() { return this._url; } /** * Creates an instance of BlobLeaseClient. * @param client - The client to make the lease operation requests. * @param leaseId - Initial proposed lease id. */ constructor(client, leaseId) { const clientContext = client.storageClientContext; this._url = client.url; if (client.name === undefined) { this._isContainer = true; this._containerOrBlobOperation = clientContext.container; } else { this._isContainer = false; this._containerOrBlobOperation = clientContext.blob; } if (!leaseId) { leaseId = randomUUID(); } this._leaseId = leaseId; } /** * Establishes and manages a lock on a container for delete operations, or on a blob * for write and delete operations. * The lock duration can be 15 to 60 seconds, or can be infinite. * @see https://learn.microsoft.com/rest/api/storageservices/lease-container * and * @see https://learn.microsoft.com/rest/api/storageservices/lease-blob * * @param duration - Must be between 15 to 60 seconds, or infinite (-1) * @param options - option to configure lease management operations. * @returns Response data for acquire lease operation. */ async acquireLease(duration, options = {}) { if (this._isContainer && ((options.conditions?.ifMatch && options.conditions?.ifMatch !== ETagNone) || (options.conditions?.ifNoneMatch && options.conditions?.ifNoneMatch !== ETagNone) || options.conditions?.tagConditions)) { throw new RangeError("The IfMatch, IfNoneMatch and tags access conditions are ignored by the service. Values other than undefined or their default values are not acceptable."); } return tracingClient.withSpan("BlobLeaseClient-acquireLease", options, async (updatedOptions) => { return assertResponse(await this._containerOrBlobOperation.acquireLease({ abortSignal: options.abortSignal, duration, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, proposedLeaseId: this._leaseId, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * To change the ID of the lease. * @see https://learn.microsoft.com/rest/api/storageservices/lease-container * and * @see https://learn.microsoft.com/rest/api/storageservices/lease-blob * * @param proposedLeaseId - the proposed new lease Id. * @param options - option to configure lease management operations. * @returns Response data for change lease operation. */ async changeLease(proposedLeaseId, options = {}) { if (this._isContainer && ((options.conditions?.ifMatch && options.conditions?.ifMatch !== ETagNone) || (options.conditions?.ifNoneMatch && options.conditions?.ifNoneMatch !== ETagNone) || options.conditions?.tagConditions)) { throw new RangeError("The IfMatch, IfNoneMatch and tags access conditions are ignored by the service. Values other than undefined or their default values are not acceptable."); } return tracingClient.withSpan("BlobLeaseClient-changeLease", options, async (updatedOptions) => { const response = assertResponse(await this._containerOrBlobOperation.changeLease(this._leaseId, proposedLeaseId, { abortSignal: options.abortSignal, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, tracingOptions: updatedOptions.tracingOptions, })); this._leaseId = proposedLeaseId; return response; }); } /** * To free the lease if it is no longer needed so that another client may * immediately acquire a lease against the container or the blob. * @see https://learn.microsoft.com/rest/api/storageservices/lease-container * and * @see https://learn.microsoft.com/rest/api/storageservices/lease-blob * * @param options - option to configure lease management operations. * @returns Response data for release lease operation. */ async releaseLease(options = {}) { if (this._isContainer && ((options.conditions?.ifMatch && options.conditions?.ifMatch !== ETagNone) || (options.conditions?.ifNoneMatch && options.conditions?.ifNoneMatch !== ETagNone) || options.conditions?.tagConditions)) { throw new RangeError("The IfMatch, IfNoneMatch and tags access conditions are ignored by the service. Values other than undefined or their default values are not acceptable."); } return tracingClient.withSpan("BlobLeaseClient-releaseLease", options, async (updatedOptions) => { return assertResponse(await this._containerOrBlobOperation.releaseLease(this._leaseId, { abortSignal: options.abortSignal, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * To renew the lease. * @see https://learn.microsoft.com/rest/api/storageservices/lease-container * and * @see https://learn.microsoft.com/rest/api/storageservices/lease-blob * * @param options - Optional option to configure lease management operations. * @returns Response data for renew lease operation. */ async renewLease(options = {}) { if (this._isContainer && ((options.conditions?.ifMatch && options.conditions?.ifMatch !== ETagNone) || (options.conditions?.ifNoneMatch && options.conditions?.ifNoneMatch !== ETagNone) || options.conditions?.tagConditions)) { throw new RangeError("The IfMatch, IfNoneMatch and tags access conditions are ignored by the service. Values other than undefined or their default values are not acceptable."); } return tracingClient.withSpan("BlobLeaseClient-renewLease", options, async (updatedOptions) => { return this._containerOrBlobOperation.renewLease(this._leaseId, { abortSignal: options.abortSignal, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, tracingOptions: updatedOptions.tracingOptions, }); }); } /** * To end the lease but ensure that another client cannot acquire a new lease * until the current lease period has expired. * @see https://learn.microsoft.com/rest/api/storageservices/lease-container * and * @see https://learn.microsoft.com/rest/api/storageservices/lease-blob * * @param breakPeriod - Break period * @param options - Optional options to configure lease management operations. * @returns Response data for break lease operation. */ async breakLease(breakPeriod, options = {}) { if (this._isContainer && ((options.conditions?.ifMatch && options.conditions?.ifMatch !== ETagNone) || (options.conditions?.ifNoneMatch && options.conditions?.ifNoneMatch !== ETagNone) || options.conditions?.tagConditions)) { throw new RangeError("The IfMatch, IfNoneMatch and tags access conditions are ignored by the service. Values other than undefined or their default values are not acceptable."); } return tracingClient.withSpan("BlobLeaseClient-breakLease", options, async (updatedOptions) => { const operationOptions = { abortSignal: options.abortSignal, breakPeriod, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, tracingOptions: updatedOptions.tracingOptions, }; return assertResponse(await this._containerOrBlobOperation.breakLease(operationOptions)); }); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. /** * This error is thrown when an asynchronous operation has been aborted. * Check for this error by testing the `name` that the name property of the * error matches `"AbortError"`. * * @example * ```ts * const controller = new AbortController(); * controller.abort(); * try { * doAsyncWork(controller.signal) * } catch (e) { * if (e.name === 'AbortError') { * // handle abort error here. * } * } * ``` */ class AbortError extends Error { constructor(message) { super(message); this.name = "AbortError"; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * A Node.js ReadableStream will internally retry when internal ReadableStream unexpected ends. */ class RetriableReadableStream extends Readable$1 { start; offset; end; getter; source; retries = 0; maxRetryRequests; onProgress; options; /** * Creates an instance of RetriableReadableStream. * * @param source - The current ReadableStream returned from getter * @param getter - A method calling downloading request returning * a new ReadableStream from specified offset * @param offset - Offset position in original data source to read * @param count - How much data in original data source to read * @param options - */ constructor(source, getter, offset, count, options = {}) { super({ highWaterMark: options.highWaterMark }); this.getter = getter; this.source = source; this.start = offset; this.offset = offset; this.end = offset + count - 1; this.maxRetryRequests = options.maxRetryRequests && options.maxRetryRequests >= 0 ? options.maxRetryRequests : 0; this.onProgress = options.onProgress; this.options = options; this.setSourceEventHandlers(); } _read() { this.source.resume(); } setSourceEventHandlers() { this.source.on("data", this.sourceDataHandler); this.source.on("end", this.sourceErrorOrEndHandler); this.source.on("error", this.sourceErrorOrEndHandler); // needed for Node14 this.source.on("aborted", this.sourceAbortedHandler); } removeSourceEventHandlers() { this.source.removeListener("data", this.sourceDataHandler); this.source.removeListener("end", this.sourceErrorOrEndHandler); this.source.removeListener("error", this.sourceErrorOrEndHandler); this.source.removeListener("aborted", this.sourceAbortedHandler); } sourceDataHandler = (data) => { if (this.options.doInjectErrorOnce) { this.options.doInjectErrorOnce = undefined; this.source.pause(); this.sourceErrorOrEndHandler(); this.source.destroy(); return; } // console.log( // `Offset: ${this.offset}, Received ${data.length} from internal stream` // ); this.offset += data.length; if (this.onProgress) { this.onProgress({ loadedBytes: this.offset - this.start }); } if (!this.push(data)) { this.source.pause(); } }; sourceAbortedHandler = () => { const abortError = new AbortError("The operation was aborted."); this.destroy(abortError); }; sourceErrorOrEndHandler = (err) => { if (err && err.name === "AbortError") { this.destroy(err); return; } // console.log( // `Source stream emits end or error, offset: ${ // this.offset // }, dest end : ${this.end}` // ); this.removeSourceEventHandlers(); if (this.offset - 1 === this.end) { this.push(null); } else if (this.offset <= this.end) { // TODO if error is CRC64 not match, directly throw out the error. // console.log( // `retries: ${this.retries}, max retries: ${this.maxRetries}` // ); if (this.retries < this.maxRetryRequests) { this.retries += 1; this.getter(this.offset) .then((newSource) => { this.source = newSource; this.setSourceEventHandlers(); return; }) .catch((error) => { this.destroy(error); }); } else { this.destroy(new Error(`Data corruption failure: received less data than required and reached maxRetires limitation. Received data offset: ${this.offset - 1}, data needed offset: ${this.end}, retries: ${this.retries}, max retries: ${this.maxRetryRequests}`)); } } else { this.destroy(new Error(`Data corruption failure: Received more data than original request, data needed offset is ${this.end}, received offset: ${this.offset - 1}`)); } }; _destroy(error, callback) { // remove listener from source and release source this.removeSourceEventHandlers(); this.source.destroy(); callback(error === null ? undefined : error); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * BlobDownloadResponse implements BlobDownloadResponseParsed interface, and in Node.js runtime it will * automatically retry when internal read stream unexpected ends. (This kind of unexpected ends cannot * trigger retries defined in pipeline retry policy.) * * The {@link readableStreamBody} stream will retry underlayer, you can just use it as a normal Node.js * Readable stream. */ class BlobDownloadResponse { /** * Indicates that the service supports * requests for partial file content. * * @readonly */ get acceptRanges() { return this.originalResponse.acceptRanges; } /** * Returns if it was previously specified * for the file. * * @readonly */ get cacheControl() { return this.originalResponse.cacheControl; } /** * Returns the value that was specified * for the 'x-ms-content-disposition' header and specifies how to process the * response. * * @readonly */ get contentDisposition() { return this.originalResponse.contentDisposition; } /** * Returns the value that was specified * for the Content-Encoding request header. * * @readonly */ get contentEncoding() { return this.originalResponse.contentEncoding; } /** * Returns the value that was specified * for the Content-Language request header. * * @readonly */ get contentLanguage() { return this.originalResponse.contentLanguage; } /** * The current sequence number for a * page blob. This header is not returned for block blobs or append blobs. * * @readonly */ get blobSequenceNumber() { return this.originalResponse.blobSequenceNumber; } /** * The blob's type. Possible values include: * 'BlockBlob', 'PageBlob', 'AppendBlob'. * * @readonly */ get blobType() { return this.originalResponse.blobType; } /** * The number of bytes present in the * response body. * * @readonly */ get contentLength() { return this.originalResponse.contentLength; } /** * If the file has an MD5 hash and the * request is to read the full file, this response header is returned so that * the client can check for message content integrity. If the request is to * read a specified range and the 'x-ms-range-get-content-md5' is set to * true, then the request returns an MD5 hash for the range, as long as the * range size is less than or equal to 4 MB. If neither of these sets of * conditions is true, then no value is returned for the 'Content-MD5' * header. * * @readonly */ get contentMD5() { return this.originalResponse.contentMD5; } /** * Indicates the range of bytes returned if * the client requested a subset of the file by setting the Range request * header. * * @readonly */ get contentRange() { return this.originalResponse.contentRange; } /** * The content type specified for the file. * The default content type is 'application/octet-stream' * * @readonly */ get contentType() { return this.originalResponse.contentType; } /** * Conclusion time of the last attempted * Copy File operation where this file was the destination file. This value * can specify the time of a completed, aborted, or failed copy attempt. * * @readonly */ get copyCompletedOn() { return this.originalResponse.copyCompletedOn; } /** * String identifier for the last attempted Copy * File operation where this file was the destination file. * * @readonly */ get copyId() { return this.originalResponse.copyId; } /** * Contains the number of bytes copied and * the total bytes in the source in the last attempted Copy File operation * where this file was the destination file. Can show between 0 and * Content-Length bytes copied. * * @readonly */ get copyProgress() { return this.originalResponse.copyProgress; } /** * URL up to 2KB in length that specifies the * source file used in the last attempted Copy File operation where this file * was the destination file. * * @readonly */ get copySource() { return this.originalResponse.copySource; } /** * State of the copy operation * identified by 'x-ms-copy-id'. Possible values include: 'pending', * 'success', 'aborted', 'failed' * * @readonly */ get copyStatus() { return this.originalResponse.copyStatus; } /** * Only appears when * x-ms-copy-status is failed or pending. Describes cause of fatal or * non-fatal copy operation failure. * * @readonly */ get copyStatusDescription() { return this.originalResponse.copyStatusDescription; } /** * When a blob is leased, * specifies whether the lease is of infinite or fixed duration. Possible * values include: 'infinite', 'fixed'. * * @readonly */ get leaseDuration() { return this.originalResponse.leaseDuration; } /** * Lease state of the blob. Possible * values include: 'available', 'leased', 'expired', 'breaking', 'broken'. * * @readonly */ get leaseState() { return this.originalResponse.leaseState; } /** * The current lease status of the * blob. Possible values include: 'locked', 'unlocked'. * * @readonly */ get leaseStatus() { return this.originalResponse.leaseStatus; } /** * A UTC date/time value generated by the service that * indicates the time at which the response was initiated. * * @readonly */ get date() { return this.originalResponse.date; } /** * The number of committed blocks * present in the blob. This header is returned only for append blobs. * * @readonly */ get blobCommittedBlockCount() { return this.originalResponse.blobCommittedBlockCount; } /** * The ETag contains a value that you can use to * perform operations conditionally, in quotes. * * @readonly */ get etag() { return this.originalResponse.etag; } /** * The number of tags associated with the blob * * @readonly */ get tagCount() { return this.originalResponse.tagCount; } /** * The error code. * * @readonly */ get errorCode() { return this.originalResponse.errorCode; } /** * The value of this header is set to * true if the file data and application metadata are completely encrypted * using the specified algorithm. Otherwise, the value is set to false (when * the file is unencrypted, or if only parts of the file/application metadata * are encrypted). * * @readonly */ get isServerEncrypted() { return this.originalResponse.isServerEncrypted; } /** * If the blob has a MD5 hash, and if * request contains range header (Range or x-ms-range), this response header * is returned with the value of the whole blob's MD5 value. This value may * or may not be equal to the value returned in Content-MD5 header, with the * latter calculated from the requested range. * * @readonly */ get blobContentMD5() { return this.originalResponse.blobContentMD5; } /** * Returns the date and time the file was last * modified. Any operation that modifies the file or its properties updates * the last modified time. * * @readonly */ get lastModified() { return this.originalResponse.lastModified; } /** * Returns the UTC date and time generated by the service that indicates the time at which the blob was * last read or written to. * * @readonly */ get lastAccessed() { return this.originalResponse.lastAccessed; } /** * Returns the date and time the blob was created. * * @readonly */ get createdOn() { return this.originalResponse.createdOn; } /** * A name-value pair * to associate with a file storage object. * * @readonly */ get metadata() { return this.originalResponse.metadata; } /** * This header uniquely identifies the request * that was made and can be used for troubleshooting the request. * * @readonly */ get requestId() { return this.originalResponse.requestId; } /** * If a client request id header is sent in the request, this header will be present in the * response with the same value. * * @readonly */ get clientRequestId() { return this.originalResponse.clientRequestId; } /** * Indicates the version of the Blob service used * to execute the request. * * @readonly */ get version() { return this.originalResponse.version; } /** * Indicates the versionId of the downloaded blob version. * * @readonly */ get versionId() { return this.originalResponse.versionId; } /** * Indicates whether version of this blob is a current version. * * @readonly */ get isCurrentVersion() { return this.originalResponse.isCurrentVersion; } /** * The SHA-256 hash of the encryption key used to encrypt the blob. This value is only returned * when the blob was encrypted with a customer-provided key. * * @readonly */ get encryptionKeySha256() { return this.originalResponse.encryptionKeySha256; } /** * If the request is to read a specified range and the x-ms-range-get-content-crc64 is set to * true, then the request returns a crc64 for the range, as long as the range size is less than * or equal to 4 MB. If both x-ms-range-get-content-crc64 & x-ms-range-get-content-md5 is * specified in the same request, it will fail with 400(Bad Request) */ get contentCrc64() { return this.originalResponse.contentCrc64; } /** * Object Replication Policy Id of the destination blob. * * @readonly */ get objectReplicationDestinationPolicyId() { return this.originalResponse.objectReplicationDestinationPolicyId; } /** * Parsed Object Replication Policy Id, Rule Id(s) and status of the source blob. * * @readonly */ get objectReplicationSourceProperties() { return this.originalResponse.objectReplicationSourceProperties; } /** * If this blob has been sealed. * * @readonly */ get isSealed() { return this.originalResponse.isSealed; } /** * UTC date/time value generated by the service that indicates the time at which the blob immutability policy will expire. * * @readonly */ get immutabilityPolicyExpiresOn() { return this.originalResponse.immutabilityPolicyExpiresOn; } /** * Indicates immutability policy mode. * * @readonly */ get immutabilityPolicyMode() { return this.originalResponse.immutabilityPolicyMode; } /** * Indicates if a legal hold is present on the blob. * * @readonly */ get legalHold() { return this.originalResponse.legalHold; } get structuredBodyType() { return this.originalResponse.structuredBodyType; } /** * The response body as a browser Blob. * Always undefined in node.js. * * @readonly */ get contentAsBlob() { return this.originalResponse.blobBody; } /** * The response body as a node.js Readable stream. * Always undefined in the browser. * * It will automatically retry when internal read stream unexpected ends. * * @readonly */ get readableStreamBody() { return this.blobDownloadStream ; } /** * The HTTP response. */ get _response() { return this.originalResponse._response; } originalResponse; blobDownloadStream; /** * Creates an instance of BlobDownloadResponse. * * @param originalResponse - * @param getter - * @param offset - * @param count - * @param options - */ constructor(originalResponse, getter, offset, count, options = {}) { this.originalResponse = originalResponse; const streamBody = this.originalResponse.structuredBodyType === undefined ? this.originalResponse.readableStreamBody : structuredMessageDecodingStream(this.originalResponse.readableStreamBody, options); this.blobDownloadStream = new RetriableReadableStream(streamBody, getter, offset, count, options); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const AVRO_SYNC_MARKER_SIZE = 16; const AVRO_INIT_BYTES = new Uint8Array([79, 98, 106, 1]); const AVRO_CODEC_KEY = "avro.codec"; const AVRO_SCHEMA_KEY = "avro.schema"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. class AvroParser { /** * Reads a fixed number of bytes from the stream. * * @param stream - * @param length - * @param options - */ static async readFixedBytes(stream, length, options = {}) { const bytes = await stream.read(length, { abortSignal: options.abortSignal }); if (bytes.length !== length) { throw new Error("Hit stream end."); } return bytes; } /** * Reads a single byte from the stream. * * @param stream - * @param options - */ static async readByte(stream, options = {}) { const buf = await AvroParser.readFixedBytes(stream, 1, options); return buf[0]; } // int and long are stored in variable-length zig-zag coding. // variable-length: https://lucene.apache.org/core/3_5_0/fileformats.html#VInt // zig-zag: https://developers.google.com/protocol-buffers/docs/encoding?csw=1#types static async readZigZagLong(stream, options = {}) { let zigZagEncoded = 0; let significanceInBit = 0; let byte, haveMoreByte, significanceInFloat; do { byte = await AvroParser.readByte(stream, options); haveMoreByte = byte & 0x80; zigZagEncoded |= (byte & 0x7f) << significanceInBit; significanceInBit += 7; } while (haveMoreByte && significanceInBit < 28); // bitwise operation only works for 32-bit integers if (haveMoreByte) { // Switch to float arithmetic // eslint-disable-next-line no-self-assign zigZagEncoded = zigZagEncoded; significanceInFloat = 268435456; // 2 ** 28. do { byte = await AvroParser.readByte(stream, options); zigZagEncoded += (byte & 0x7f) * significanceInFloat; significanceInFloat *= 128; // 2 ** 7 } while (byte & 0x80); const res = (zigZagEncoded % 2 ? -(zigZagEncoded + 1) : zigZagEncoded) / 2; if (res < Number.MIN_SAFE_INTEGER || res > Number.MAX_SAFE_INTEGER) { throw new Error("Integer overflow."); } return res; } return (zigZagEncoded >> 1) ^ -(zigZagEncoded & 1); } static async readLong(stream, options = {}) { return AvroParser.readZigZagLong(stream, options); } static async readInt(stream, options = {}) { return AvroParser.readZigZagLong(stream, options); } static async readNull() { return null; } static async readBoolean(stream, options = {}) { const b = await AvroParser.readByte(stream, options); if (b === 1) { return true; } else if (b === 0) { return false; } else { throw new Error("Byte was not a boolean."); } } static async readFloat(stream, options = {}) { const u8arr = await AvroParser.readFixedBytes(stream, 4, options); const view = new DataView(u8arr.buffer, u8arr.byteOffset, u8arr.byteLength); return view.getFloat32(0, true); // littleEndian = true } static async readDouble(stream, options = {}) { const u8arr = await AvroParser.readFixedBytes(stream, 8, options); const view = new DataView(u8arr.buffer, u8arr.byteOffset, u8arr.byteLength); return view.getFloat64(0, true); // littleEndian = true } static async readBytes(stream, options = {}) { const size = await AvroParser.readLong(stream, options); if (size < 0) { throw new Error("Bytes size was negative."); } return stream.read(size, { abortSignal: options.abortSignal }); } static async readString(stream, options = {}) { const u8arr = await AvroParser.readBytes(stream, options); const utf8decoder = new TextDecoder(); return utf8decoder.decode(u8arr); } static async readMapPair(stream, readItemMethod, options = {}) { const key = await AvroParser.readString(stream, options); // FUTURE: this won't work with readFixed (currently not supported) which needs a length as the parameter. const value = await readItemMethod(stream, options); return { key, value }; } static async readMap(stream, readItemMethod, options = {}) { const readPairMethod = (s, opts = {}) => { return AvroParser.readMapPair(s, readItemMethod, opts); }; const pairs = await AvroParser.readArray(stream, readPairMethod, options); const dict = {}; for (const pair of pairs) { dict[pair.key] = pair.value; } return dict; } static async readArray(stream, readItemMethod, options = {}) { const items = []; for (let count = await AvroParser.readLong(stream, options); count !== 0; count = await AvroParser.readLong(stream, options)) { if (count < 0) { // Ignore block sizes await AvroParser.readLong(stream, options); count = -count; } while (count--) { const item = await readItemMethod(stream, options); items.push(item); } } return items; } } var AvroComplex; (function (AvroComplex) { AvroComplex["RECORD"] = "record"; AvroComplex["ENUM"] = "enum"; AvroComplex["ARRAY"] = "array"; AvroComplex["MAP"] = "map"; AvroComplex["UNION"] = "union"; AvroComplex["FIXED"] = "fixed"; })(AvroComplex || (AvroComplex = {})); var AvroPrimitive; (function (AvroPrimitive) { AvroPrimitive["NULL"] = "null"; AvroPrimitive["BOOLEAN"] = "boolean"; AvroPrimitive["INT"] = "int"; AvroPrimitive["LONG"] = "long"; AvroPrimitive["FLOAT"] = "float"; AvroPrimitive["DOUBLE"] = "double"; AvroPrimitive["BYTES"] = "bytes"; AvroPrimitive["STRING"] = "string"; })(AvroPrimitive || (AvroPrimitive = {})); class AvroType { /** * Determines the AvroType from the Avro Schema. */ // eslint-disable-next-line @typescript-eslint/no-wrapper-object-types static fromSchema(schema) { if (typeof schema === "string") { return AvroType.fromStringSchema(schema); } else if (Array.isArray(schema)) { return AvroType.fromArraySchema(schema); } else { return AvroType.fromObjectSchema(schema); } } static fromStringSchema(schema) { switch (schema) { case AvroPrimitive.NULL: case AvroPrimitive.BOOLEAN: case AvroPrimitive.INT: case AvroPrimitive.LONG: case AvroPrimitive.FLOAT: case AvroPrimitive.DOUBLE: case AvroPrimitive.BYTES: case AvroPrimitive.STRING: return new AvroPrimitiveType(schema); default: throw new Error(`Unexpected Avro type ${schema}`); } } static fromArraySchema(schema) { return new AvroUnionType(schema.map(AvroType.fromSchema)); } static fromObjectSchema(schema) { const type = schema.type; // Primitives can be defined as strings or objects try { return AvroType.fromStringSchema(type); } catch { // no-op } switch (type) { case AvroComplex.RECORD: if (schema.aliases) { throw new Error(`aliases currently is not supported, schema: ${schema}`); } if (!schema.name) { throw new Error(`Required attribute 'name' doesn't exist on schema: ${schema}`); } // eslint-disable-next-line no-case-declarations const fields = {}; if (!schema.fields) { throw new Error(`Required attribute 'fields' doesn't exist on schema: ${schema}`); } for (const field of schema.fields) { fields[field.name] = AvroType.fromSchema(field.type); } return new AvroRecordType(fields, schema.name); case AvroComplex.ENUM: if (schema.aliases) { throw new Error(`aliases currently is not supported, schema: ${schema}`); } if (!schema.symbols) { throw new Error(`Required attribute 'symbols' doesn't exist on schema: ${schema}`); } return new AvroEnumType(schema.symbols); case AvroComplex.MAP: if (!schema.values) { throw new Error(`Required attribute 'values' doesn't exist on schema: ${schema}`); } return new AvroMapType(AvroType.fromSchema(schema.values)); case AvroComplex.ARRAY: // Unused today case AvroComplex.FIXED: // Unused today default: throw new Error(`Unexpected Avro type ${type} in ${schema}`); } } } class AvroPrimitiveType extends AvroType { _primitive; constructor(primitive) { super(); this._primitive = primitive; } // eslint-disable-next-line @typescript-eslint/no-wrapper-object-types read(stream, options = {}) { switch (this._primitive) { case AvroPrimitive.NULL: return AvroParser.readNull(); case AvroPrimitive.BOOLEAN: return AvroParser.readBoolean(stream, options); case AvroPrimitive.INT: return AvroParser.readInt(stream, options); case AvroPrimitive.LONG: return AvroParser.readLong(stream, options); case AvroPrimitive.FLOAT: return AvroParser.readFloat(stream, options); case AvroPrimitive.DOUBLE: return AvroParser.readDouble(stream, options); case AvroPrimitive.BYTES: return AvroParser.readBytes(stream, options); case AvroPrimitive.STRING: return AvroParser.readString(stream, options); default: throw new Error("Unknown Avro Primitive"); } } } class AvroEnumType extends AvroType { _symbols; constructor(symbols) { super(); this._symbols = symbols; } // eslint-disable-next-line @typescript-eslint/no-wrapper-object-types async read(stream, options = {}) { const value = await AvroParser.readInt(stream, options); return this._symbols[value]; } } class AvroUnionType extends AvroType { _types; constructor(types) { super(); this._types = types; } async read(stream, options = {}) { const typeIndex = await AvroParser.readInt(stream, options); return this._types[typeIndex].read(stream, options); } } class AvroMapType extends AvroType { _itemType; constructor(itemType) { super(); this._itemType = itemType; } // eslint-disable-next-line @typescript-eslint/no-wrapper-object-types read(stream, options = {}) { const readItemMethod = (s, opts) => { return this._itemType.read(s, opts); }; return AvroParser.readMap(stream, readItemMethod, options); } } class AvroRecordType extends AvroType { _name; _fields; constructor(fields, name) { super(); this._fields = fields; this._name = name; } // eslint-disable-next-line @typescript-eslint/no-wrapper-object-types async read(stream, options = {}) { // eslint-disable-next-line @typescript-eslint/no-wrapper-object-types const record = {}; record["$schema"] = this._name; for (const key in this._fields) { if (Object.prototype.hasOwnProperty.call(this._fields, key)) { record[key] = await this._fields[key].read(stream, options); } } return record; } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. function arraysEqual(a, b) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; for (let i = 0; i < a.length; ++i) { if (a[i] !== b[i]) return false; } return true; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // TODO: Do a review of non-interfaces /* eslint-disable @azure/azure-sdk/ts-use-interface-parameters */ class AvroReader { _dataStream; _headerStream; _syncMarker; _metadata; _itemType; _itemsRemainingInBlock; // Remembers where we started if partial data stream was provided. _initialBlockOffset; /// The byte offset within the Avro file (both header and data) /// of the start of the current block. _blockOffset; get blockOffset() { return this._blockOffset; } _objectIndex; get objectIndex() { return this._objectIndex; } _initialized; constructor(dataStream, headerStream, currentBlockOffset, indexWithinCurrentBlock) { this._dataStream = dataStream; this._headerStream = headerStream || dataStream; this._initialized = false; this._blockOffset = currentBlockOffset || 0; this._objectIndex = indexWithinCurrentBlock || 0; this._initialBlockOffset = currentBlockOffset || 0; } async initialize(options = {}) { const header = await AvroParser.readFixedBytes(this._headerStream, AVRO_INIT_BYTES.length, { abortSignal: options.abortSignal, }); if (!arraysEqual(header, AVRO_INIT_BYTES)) { throw new Error("Stream is not an Avro file."); } // File metadata is written as if defined by the following map schema: // { "type": "map", "values": "bytes"} this._metadata = await AvroParser.readMap(this._headerStream, AvroParser.readString, { abortSignal: options.abortSignal, }); // Validate codec const codec = this._metadata[AVRO_CODEC_KEY]; if (!(codec === undefined || codec === null || codec === "null")) { throw new Error("Codecs are not supported"); } // The 16-byte, randomly-generated sync marker for this file. this._syncMarker = await AvroParser.readFixedBytes(this._headerStream, AVRO_SYNC_MARKER_SIZE, { abortSignal: options.abortSignal, }); // Parse the schema const schema = JSON.parse(this._metadata[AVRO_SCHEMA_KEY]); this._itemType = AvroType.fromSchema(schema); if (this._blockOffset === 0) { this._blockOffset = this._initialBlockOffset + this._dataStream.position; } this._itemsRemainingInBlock = await AvroParser.readLong(this._dataStream, { abortSignal: options.abortSignal, }); // skip block length await AvroParser.readLong(this._dataStream, { abortSignal: options.abortSignal }); this._initialized = true; if (this._objectIndex && this._objectIndex > 0) { for (let i = 0; i < this._objectIndex; i++) { await this._itemType.read(this._dataStream, { abortSignal: options.abortSignal }); this._itemsRemainingInBlock--; } } } hasNext() { return !this._initialized || this._itemsRemainingInBlock > 0; } async *parseObjects(options = {}) { if (!this._initialized) { await this.initialize(options); } while (this.hasNext()) { const result = await this._itemType.read(this._dataStream, { abortSignal: options.abortSignal, }); this._itemsRemainingInBlock--; this._objectIndex++; if (this._itemsRemainingInBlock === 0) { const marker = await AvroParser.readFixedBytes(this._dataStream, AVRO_SYNC_MARKER_SIZE, { abortSignal: options.abortSignal, }); this._blockOffset = this._initialBlockOffset + this._dataStream.position; this._objectIndex = 0; if (!arraysEqual(this._syncMarker, marker)) { throw new Error("Stream is not a valid Avro file."); } try { this._itemsRemainingInBlock = await AvroParser.readLong(this._dataStream, { abortSignal: options.abortSignal, }); } catch { // We hit the end of the stream. this._itemsRemainingInBlock = 0; } if (this._itemsRemainingInBlock > 0) { // Ignore block size await AvroParser.readLong(this._dataStream, { abortSignal: options.abortSignal }); } } yield result; } } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. class AvroReadable { } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. const ABORT_ERROR = new AbortError("Reading from the avro stream was aborted."); class AvroReadableFromStream extends AvroReadable { _position; _readable; toUint8Array(data) { if (typeof data === "string") { return Buffer$1.from(data); } return data; } constructor(readable) { super(); this._readable = readable; this._position = 0; } get position() { return this._position; } async read(size, options = {}) { if (options.abortSignal?.aborted) { throw ABORT_ERROR; } if (size < 0) { throw new Error(`size parameter should be positive: ${size}`); } if (size === 0) { return new Uint8Array(); } if (!this._readable.readable) { throw new Error("Stream no longer readable."); } // See if there is already enough data. const chunk = this._readable.read(size); if (chunk) { this._position += chunk.length; // chunk.length maybe less than desired size if the stream ends. return this.toUint8Array(chunk); } else { // register callback to wait for enough data to read return new Promise((resolve, reject) => { /* eslint-disable @typescript-eslint/no-use-before-define */ const cleanUp = () => { this._readable.removeListener("readable", readableCallback); this._readable.removeListener("error", rejectCallback); this._readable.removeListener("end", rejectCallback); this._readable.removeListener("close", rejectCallback); if (options.abortSignal) { options.abortSignal.removeEventListener("abort", abortHandler); } }; const readableCallback = () => { const callbackChunk = this._readable.read(size); if (callbackChunk) { this._position += callbackChunk.length; cleanUp(); // callbackChunk.length maybe less than desired size if the stream ends. resolve(this.toUint8Array(callbackChunk)); } }; const rejectCallback = () => { cleanUp(); reject(); }; const abortHandler = () => { cleanUp(); reject(ABORT_ERROR); }; this._readable.on("readable", readableCallback); this._readable.once("error", rejectCallback); this._readable.once("end", rejectCallback); this._readable.once("close", rejectCallback); if (options.abortSignal) { options.abortSignal.addEventListener("abort", abortHandler); } /* eslint-enable @typescript-eslint/no-use-before-define */ }); } } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * A Node.js BlobQuickQueryStream will internally parse avro data stream for blob query. */ class BlobQuickQueryStream extends Readable$1 { source; avroReader; avroIter; avroPaused = true; onProgress; onError; /** * Creates an instance of BlobQuickQueryStream. * * @param source - The current ReadableStream returned from getter * @param options - */ constructor(source, options = {}) { super(); this.source = source; this.onProgress = options.onProgress; this.onError = options.onError; this.avroReader = new AvroReader(new AvroReadableFromStream(this.source)); this.avroIter = this.avroReader.parseObjects({ abortSignal: options.abortSignal }); } _read() { if (this.avroPaused) { this.readInternal().catch((err) => { this.emit("error", err); }); } } async readInternal() { this.avroPaused = false; let avroNext; do { avroNext = await this.avroIter.next(); if (avroNext.done) { break; } const obj = avroNext.value; const schema = obj.$schema; if (typeof schema !== "string") { throw Error("Missing schema in avro record."); } switch (schema) { case "com.microsoft.azure.storage.queryBlobContents.resultData": { const data = obj.data; if (data instanceof Uint8Array === false) { throw Error("Invalid data in avro result record."); } if (!this.push(Buffer.from(data))) { this.avroPaused = true; } } break; case "com.microsoft.azure.storage.queryBlobContents.progress": { const bytesScanned = obj.bytesScanned; if (typeof bytesScanned !== "number") { throw Error("Invalid bytesScanned in avro progress record."); } if (this.onProgress) { this.onProgress({ loadedBytes: bytesScanned }); } } break; case "com.microsoft.azure.storage.queryBlobContents.end": if (this.onProgress) { const totalBytes = obj.totalBytes; if (typeof totalBytes !== "number") { throw Error("Invalid totalBytes in avro end record."); } this.onProgress({ loadedBytes: totalBytes }); } this.push(null); break; case "com.microsoft.azure.storage.queryBlobContents.error": if (this.onError) { const fatal = obj.fatal; if (typeof fatal !== "boolean") { throw Error("Invalid fatal in avro error record."); } const name = obj.name; if (typeof name !== "string") { throw Error("Invalid name in avro error record."); } const description = obj.description; if (typeof description !== "string") { throw Error("Invalid description in avro error record."); } const position = obj.position; if (typeof position !== "number") { throw Error("Invalid position in avro error record."); } this.onError({ position, name, isFatal: fatal, description, }); } break; default: throw Error(`Unknown schema ${schema} in avro progress record.`); } } while (!avroNext.done && !this.avroPaused); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * BlobQueryResponse implements BlobDownloadResponseModel interface, and in Node.js runtime it will * parse avro data returned by blob query. */ class BlobQueryResponse { /** * Indicates that the service supports * requests for partial file content. * * @readonly */ get acceptRanges() { return this.originalResponse.acceptRanges; } /** * Returns if it was previously specified * for the file. * * @readonly */ get cacheControl() { return this.originalResponse.cacheControl; } /** * Returns the value that was specified * for the 'x-ms-content-disposition' header and specifies how to process the * response. * * @readonly */ get contentDisposition() { return this.originalResponse.contentDisposition; } /** * Returns the value that was specified * for the Content-Encoding request header. * * @readonly */ get contentEncoding() { return this.originalResponse.contentEncoding; } /** * Returns the value that was specified * for the Content-Language request header. * * @readonly */ get contentLanguage() { return this.originalResponse.contentLanguage; } /** * The current sequence number for a * page blob. This header is not returned for block blobs or append blobs. * * @readonly */ get blobSequenceNumber() { return this.originalResponse.blobSequenceNumber; } /** * The blob's type. Possible values include: * 'BlockBlob', 'PageBlob', 'AppendBlob'. * * @readonly */ get blobType() { return this.originalResponse.blobType; } /** * The number of bytes present in the * response body. * * @readonly */ get contentLength() { return this.originalResponse.contentLength; } /** * If the file has an MD5 hash and the * request is to read the full file, this response header is returned so that * the client can check for message content integrity. If the request is to * read a specified range and the 'x-ms-range-get-content-md5' is set to * true, then the request returns an MD5 hash for the range, as long as the * range size is less than or equal to 4 MB. If neither of these sets of * conditions is true, then no value is returned for the 'Content-MD5' * header. * * @readonly */ get contentMD5() { return this.originalResponse.contentMD5; } /** * Indicates the range of bytes returned if * the client requested a subset of the file by setting the Range request * header. * * @readonly */ get contentRange() { return this.originalResponse.contentRange; } /** * The content type specified for the file. * The default content type is 'application/octet-stream' * * @readonly */ get contentType() { return this.originalResponse.contentType; } /** * Conclusion time of the last attempted * Copy File operation where this file was the destination file. This value * can specify the time of a completed, aborted, or failed copy attempt. * * @readonly */ get copyCompletedOn() { return undefined; } /** * String identifier for the last attempted Copy * File operation where this file was the destination file. * * @readonly */ get copyId() { return this.originalResponse.copyId; } /** * Contains the number of bytes copied and * the total bytes in the source in the last attempted Copy File operation * where this file was the destination file. Can show between 0 and * Content-Length bytes copied. * * @readonly */ get copyProgress() { return this.originalResponse.copyProgress; } /** * URL up to 2KB in length that specifies the * source file used in the last attempted Copy File operation where this file * was the destination file. * * @readonly */ get copySource() { return this.originalResponse.copySource; } /** * State of the copy operation * identified by 'x-ms-copy-id'. Possible values include: 'pending', * 'success', 'aborted', 'failed' * * @readonly */ get copyStatus() { return this.originalResponse.copyStatus; } /** * Only appears when * x-ms-copy-status is failed or pending. Describes cause of fatal or * non-fatal copy operation failure. * * @readonly */ get copyStatusDescription() { return this.originalResponse.copyStatusDescription; } /** * When a blob is leased, * specifies whether the lease is of infinite or fixed duration. Possible * values include: 'infinite', 'fixed'. * * @readonly */ get leaseDuration() { return this.originalResponse.leaseDuration; } /** * Lease state of the blob. Possible * values include: 'available', 'leased', 'expired', 'breaking', 'broken'. * * @readonly */ get leaseState() { return this.originalResponse.leaseState; } /** * The current lease status of the * blob. Possible values include: 'locked', 'unlocked'. * * @readonly */ get leaseStatus() { return this.originalResponse.leaseStatus; } /** * A UTC date/time value generated by the service that * indicates the time at which the response was initiated. * * @readonly */ get date() { return this.originalResponse.date; } /** * The number of committed blocks * present in the blob. This header is returned only for append blobs. * * @readonly */ get blobCommittedBlockCount() { return this.originalResponse.blobCommittedBlockCount; } /** * The ETag contains a value that you can use to * perform operations conditionally, in quotes. * * @readonly */ get etag() { return this.originalResponse.etag; } /** * The error code. * * @readonly */ get errorCode() { return this.originalResponse.errorCode; } /** * The value of this header is set to * true if the file data and application metadata are completely encrypted * using the specified algorithm. Otherwise, the value is set to false (when * the file is unencrypted, or if only parts of the file/application metadata * are encrypted). * * @readonly */ get isServerEncrypted() { return this.originalResponse.isServerEncrypted; } /** * If the blob has a MD5 hash, and if * request contains range header (Range or x-ms-range), this response header * is returned with the value of the whole blob's MD5 value. This value may * or may not be equal to the value returned in Content-MD5 header, with the * latter calculated from the requested range. * * @readonly */ get blobContentMD5() { return this.originalResponse.blobContentMD5; } /** * Returns the date and time the file was last * modified. Any operation that modifies the file or its properties updates * the last modified time. * * @readonly */ get lastModified() { return this.originalResponse.lastModified; } /** * A name-value pair * to associate with a file storage object. * * @readonly */ get metadata() { return this.originalResponse.metadata; } /** * This header uniquely identifies the request * that was made and can be used for troubleshooting the request. * * @readonly */ get requestId() { return this.originalResponse.requestId; } /** * If a client request id header is sent in the request, this header will be present in the * response with the same value. * * @readonly */ get clientRequestId() { return this.originalResponse.clientRequestId; } /** * Indicates the version of the File service used * to execute the request. * * @readonly */ get version() { return this.originalResponse.version; } /** * The SHA-256 hash of the encryption key used to encrypt the blob. This value is only returned * when the blob was encrypted with a customer-provided key. * * @readonly */ get encryptionKeySha256() { return this.originalResponse.encryptionKeySha256; } /** * If the request is to read a specified range and the x-ms-range-get-content-crc64 is set to * true, then the request returns a crc64 for the range, as long as the range size is less than * or equal to 4 MB. If both x-ms-range-get-content-crc64 & x-ms-range-get-content-md5 is * specified in the same request, it will fail with 400(Bad Request) */ get contentCrc64() { return this.originalResponse.contentCrc64; } /** * The response body as a browser Blob. * Always undefined in node.js. * * @readonly */ get blobBody() { return undefined; } /** * The response body as a node.js Readable stream. * Always undefined in the browser. * * It will parse avor data returned by blob query. * * @readonly */ get readableStreamBody() { return this.blobDownloadStream ; } /** * The HTTP response. */ get _response() { return this.originalResponse._response; } originalResponse; blobDownloadStream; /** * Creates an instance of BlobQueryResponse. * * @param originalResponse - * @param options - */ constructor(originalResponse, options = {}) { this.originalResponse = originalResponse; this.blobDownloadStream = new BlobQuickQueryStream(this.originalResponse.readableStreamBody, options); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Represents the access tier on a blob. * For detailed information about block blob level tiering see {@link https://learn.microsoft.com/azure/storage/blobs/storage-blob-storage-tiers|Hot, cool and archive storage tiers.} */ var BlockBlobTier; (function (BlockBlobTier) { /** * Optimized for storing data that is accessed frequently. */ BlockBlobTier["Hot"] = "Hot"; /** * Optimized for storing data that is infrequently accessed and stored for at least 30 days. */ BlockBlobTier["Cool"] = "Cool"; /** * Optimized for storing data that is rarely accessed. */ BlockBlobTier["Cold"] = "Cold"; /** * Optimized for storing data that is rarely accessed and stored for at least 180 days * with flexible latency requirements (on the order of hours). */ BlockBlobTier["Archive"] = "Archive"; })(BlockBlobTier || (BlockBlobTier = {})); /** * Specifies the page blob tier to set the blob to. This is only applicable to page blobs on premium storage accounts. * Please see {@link https://learn.microsoft.com/azure/storage/storage-premium-storage#scalability-and-performance-targets|here} * for detailed information on the corresponding IOPS and throughput per PageBlobTier. */ var PremiumPageBlobTier; (function (PremiumPageBlobTier) { /** * P4 Tier. */ PremiumPageBlobTier["P4"] = "P4"; /** * P6 Tier. */ PremiumPageBlobTier["P6"] = "P6"; /** * P10 Tier. */ PremiumPageBlobTier["P10"] = "P10"; /** * P15 Tier. */ PremiumPageBlobTier["P15"] = "P15"; /** * P20 Tier. */ PremiumPageBlobTier["P20"] = "P20"; /** * P30 Tier. */ PremiumPageBlobTier["P30"] = "P30"; /** * P40 Tier. */ PremiumPageBlobTier["P40"] = "P40"; /** * P50 Tier. */ PremiumPageBlobTier["P50"] = "P50"; /** * P60 Tier. */ PremiumPageBlobTier["P60"] = "P60"; /** * P70 Tier. */ PremiumPageBlobTier["P70"] = "P70"; /** * P80 Tier. */ PremiumPageBlobTier["P80"] = "P80"; })(PremiumPageBlobTier || (PremiumPageBlobTier = {})); function toAccessTier(tier) { if (tier === undefined) { return undefined; } return tier; // No more check if string is a valid AccessTier, and left this to underlay logic to decide(service). } function ensureCpkIfSpecified(cpk, isHttps) { if (cpk && !isHttps) { throw new RangeError("Customer-provided encryption key must be used over HTTPS."); } if (cpk && !cpk.encryptionAlgorithm) { cpk.encryptionAlgorithm = EncryptionAlgorithmAES25; } } /** * Defines the known cloud audiences for Storage. */ var StorageBlobAudience; (function (StorageBlobAudience) { /** * The OAuth scope to use to retrieve an AAD token for Azure Storage. */ StorageBlobAudience["StorageOAuthScopes"] = "https://storage.azure.com/.default"; /** * The OAuth scope to use to retrieve an AAD token for Azure Disk. */ StorageBlobAudience["DiskComputeOAuthScopes"] = "https://disk.compute.azure.com/.default"; })(StorageBlobAudience || (StorageBlobAudience = {})); // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Function that converts PageRange and ClearRange to a common Range object. * PageRange and ClearRange have start and end while Range offset and count * this function normalizes to Range. * @param response - Model PageBlob Range response */ function rangeResponseFromModel(response) { const pageRange = (response._response.parsedBody.pageRange || []).map((x) => ({ offset: x.start, count: x.end - x.start, })); const clearRange = (response._response.parsedBody.clearRange || []).map((x) => ({ offset: x.start, count: x.end - x.start, })); return { ...response, pageRange, clearRange, _response: { ...response._response, parsedBody: { pageRange, clearRange, }, }, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. /** * When a poller is manually stopped through the `stopPolling` method, * the poller will be rejected with an instance of the PollerStoppedError. */ class PollerStoppedError extends Error { constructor(message) { super(message); this.name = "PollerStoppedError"; Object.setPrototypeOf(this, PollerStoppedError.prototype); } } /** * When the operation is cancelled, the poller will be rejected with an instance * of the PollerCancelledError. */ class PollerCancelledError extends Error { constructor(message) { super(message); this.name = "PollerCancelledError"; Object.setPrototypeOf(this, PollerCancelledError.prototype); } } /** * A class that represents the definition of a program that polls through consecutive requests * until it reaches a state of completion. * * A poller can be executed manually, by polling request by request by calling to the `poll()` method repeatedly, until its operation is completed. * It also provides a way to wait until the operation completes, by calling `pollUntilDone()` and waiting until the operation finishes. * Pollers can also request the cancellation of the ongoing process to whom is providing the underlying long running operation. * * ```ts * const poller = new MyPoller(); * * // Polling just once: * await poller.poll(); * * // We can try to cancel the request here, by calling: * // * // await poller.cancelOperation(); * // * * // Getting the final result: * const result = await poller.pollUntilDone(); * ``` * * The Poller is defined by two types, a type representing the state of the poller, which * must include a basic set of properties from `PollOperationState`, * and a return type defined by `TResult`, which can be anything. * * The Poller class implements the `PollerLike` interface, which allows poller implementations to avoid having * to export the Poller's class directly, and instead only export the already instantiated poller with the PollerLike type. * * ```ts * class Client { * public async makePoller: PollerLike { * const poller = new MyPoller({}); * // It might be preferred to return the poller after the first request is made, * // so that some information can be obtained right away. * await poller.poll(); * return poller; * } * } * * const poller: PollerLike = myClient.makePoller(); * ``` * * A poller can be created through its constructor, then it can be polled until it's completed. * At any point in time, the state of the poller can be obtained without delay through the getOperationState method. * At any point in time, the intermediate forms of the result type can be requested without delay. * Once the underlying operation is marked as completed, the poller will stop and the final value will be returned. * * ```ts * const poller = myClient.makePoller(); * const state: MyOperationState = poller.getOperationState(); * * // The intermediate result can be obtained at any time. * const result: MyResult | undefined = poller.getResult(); * * // The final result can only be obtained after the poller finishes. * const result: MyResult = await poller.pollUntilDone(); * ``` * */ // eslint-disable-next-line no-use-before-define class Poller { /** * A poller needs to be initialized by passing in at least the basic properties of the `PollOperation`. * * When writing an implementation of a Poller, this implementation needs to deal with the initialization * of any custom state beyond the basic definition of the poller. The basic poller assumes that the poller's * operation has already been defined, at least its basic properties. The code below shows how to approach * the definition of the constructor of a new custom poller. * * ```ts * export class MyPoller extends Poller { * constructor({ * // Anything you might need outside of the basics * }) { * let state: MyOperationState = { * privateProperty: private, * publicProperty: public, * }; * * const operation = { * state, * update, * cancel, * toString * } * * // Sending the operation to the parent's constructor. * super(operation); * * // You can assign more local properties here. * } * } * ``` * * Inside of this constructor, a new promise is created. This will be used to * tell the user when the poller finishes (see `pollUntilDone()`). The promise's * resolve and reject methods are also used internally to control when to resolve * or reject anyone waiting for the poller to finish. * * The constructor of a custom implementation of a poller is where any serialized version of * a previous poller's operation should be deserialized into the operation sent to the * base constructor. For example: * * ```ts * export class MyPoller extends Poller { * constructor( * baseOperation: string | undefined * ) { * let state: MyOperationState = {}; * if (baseOperation) { * state = { * ...JSON.parse(baseOperation).state, * ...state * }; * } * const operation = { * state, * // ... * } * super(operation); * } * } * ``` * * @param operation - Must contain the basic properties of `PollOperation`. */ constructor(operation) { /** controls whether to throw an error if the operation failed or was canceled. */ this.resolveOnUnsuccessful = false; this.stopped = true; this.pollProgressCallbacks = []; this.operation = operation; this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); // This prevents the UnhandledPromiseRejectionWarning in node.js from being thrown. // The above warning would get thrown if `poller.poll` is called, it returns an error, // and pullUntilDone did not have a .catch or await try/catch on it's return value. this.promise.catch(() => { /* intentionally blank */ }); } /** * Starts a loop that will break only if the poller is done * or if the poller is stopped. */ async startPolling(pollOptions = {}) { if (this.stopped) { this.stopped = false; } while (!this.isStopped() && !this.isDone()) { await this.poll(pollOptions); await this.delay(); } } /** * pollOnce does one polling, by calling to the update method of the underlying * poll operation to make any relevant change effective. * * It only optionally receives an object with an abortSignal property, from \@azure/abort-controller's AbortSignalLike. * * @param options - Optional properties passed to the operation's update method. */ async pollOnce(options = {}) { if (!this.isDone()) { this.operation = await this.operation.update({ abortSignal: options.abortSignal, fireProgress: this.fireProgress.bind(this), }); } this.processUpdatedState(); } /** * fireProgress calls the functions passed in via onProgress the method of the poller. * * It loops over all of the callbacks received from onProgress, and executes them, sending them * the current operation state. * * @param state - The current operation state. */ fireProgress(state) { for (const callback of this.pollProgressCallbacks) { callback(state); } } /** * Invokes the underlying operation's cancel method. */ async cancelOnce(options = {}) { this.operation = await this.operation.cancel(options); } /** * Returns a promise that will resolve once a single polling request finishes. * It does this by calling the update method of the Poller's operation. * * It only optionally receives an object with an abortSignal property, from \@azure/abort-controller's AbortSignalLike. * * @param options - Optional properties passed to the operation's update method. */ poll(options = {}) { if (!this.pollOncePromise) { this.pollOncePromise = this.pollOnce(options); const clearPollOncePromise = () => { this.pollOncePromise = undefined; }; this.pollOncePromise.then(clearPollOncePromise, clearPollOncePromise).catch(this.reject); } return this.pollOncePromise; } processUpdatedState() { if (this.operation.state.error) { this.stopped = true; if (!this.resolveOnUnsuccessful) { this.reject(this.operation.state.error); throw this.operation.state.error; } } if (this.operation.state.isCancelled) { this.stopped = true; if (!this.resolveOnUnsuccessful) { const error = new PollerCancelledError("Operation was canceled"); this.reject(error); throw error; } } if (this.isDone() && this.resolve) { // If the poller has finished polling, this means we now have a result. // However, it can be the case that TResult is instantiated to void, so // we are not expecting a result anyway. To assert that we might not // have a result eventually after finishing polling, we cast the result // to TResult. this.resolve(this.getResult()); } } /** * Returns a promise that will resolve once the underlying operation is completed. */ async pollUntilDone(pollOptions = {}) { if (this.stopped) { this.startPolling(pollOptions).catch(this.reject); } // This is needed because the state could have been updated by // `cancelOperation`, e.g. the operation is canceled or an error occurred. this.processUpdatedState(); return this.promise; } /** * Invokes the provided callback after each polling is completed, * sending the current state of the poller's operation. * * It returns a method that can be used to stop receiving updates on the given callback function. */ onProgress(callback) { this.pollProgressCallbacks.push(callback); return () => { this.pollProgressCallbacks = this.pollProgressCallbacks.filter((c) => c !== callback); }; } /** * Returns true if the poller has finished polling. */ isDone() { const state = this.operation.state; return Boolean(state.isCompleted || state.isCancelled || state.error); } /** * Stops the poller from continuing to poll. */ stopPolling() { if (!this.stopped) { this.stopped = true; if (this.reject) { this.reject(new PollerStoppedError("This poller is already stopped")); } } } /** * Returns true if the poller is stopped. */ isStopped() { return this.stopped; } /** * Attempts to cancel the underlying operation. * * It only optionally receives an object with an abortSignal property, from \@azure/abort-controller's AbortSignalLike. * * If it's called again before it finishes, it will throw an error. * * @param options - Optional properties passed to the operation's update method. */ cancelOperation(options = {}) { if (!this.cancelPromise) { this.cancelPromise = this.cancelOnce(options); } else if (options.abortSignal) { throw new Error("A cancel request is currently pending"); } return this.cancelPromise; } /** * Returns the state of the operation. * * Even though TState will be the same type inside any of the methods of any extension of the Poller class, * implementations of the pollers can customize what's shared with the public by writing their own * version of the `getOperationState` method, and by defining two types, one representing the internal state of the poller * and a public type representing a safe to share subset of the properties of the internal state. * Their definition of getOperationState can then return their public type. * * Example: * * ```ts * // Let's say we have our poller's operation state defined as: * interface MyOperationState extends PollOperationState { * privateProperty?: string; * publicProperty?: string; * } * * // To allow us to have a true separation of public and private state, we have to define another interface: * interface PublicState extends PollOperationState { * publicProperty?: string; * } * * // Then, we define our Poller as follows: * export class MyPoller extends Poller { * // ... More content is needed here ... * * public getOperationState(): PublicState { * const state: PublicState = this.operation.state; * return { * // Properties from PollOperationState * isStarted: state.isStarted, * isCompleted: state.isCompleted, * isCancelled: state.isCancelled, * error: state.error, * result: state.result, * * // The only other property needed by PublicState. * publicProperty: state.publicProperty * } * } * } * ``` * * You can see this in the tests of this repository, go to the file: * `../test/utils/testPoller.ts` * and look for the getOperationState implementation. */ getOperationState() { return this.operation.state; } /** * Returns the result value of the operation, * regardless of the state of the poller. * It can return undefined or an incomplete form of the final TResult value * depending on the implementation. */ getResult() { const state = this.operation.state; return state.result; } /** * Returns a serialized version of the poller's operation * by invoking the operation's toString method. */ toString() { return this.operation.toString(); } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * This is the poller returned by {@link BlobClient.beginCopyFromURL}. * This can not be instantiated directly outside of this package. * * @hidden */ class BlobBeginCopyFromUrlPoller extends Poller { intervalInMs; constructor(options) { const { blobClient, copySource, intervalInMs = 15000, onProgress, resumeFrom, startCopyFromURLOptions, } = options; let state; if (resumeFrom) { state = JSON.parse(resumeFrom).state; } const operation = makeBlobBeginCopyFromURLPollOperation({ ...state, blobClient, copySource, startCopyFromURLOptions, }); super(operation); if (typeof onProgress === "function") { this.onProgress(onProgress); } this.intervalInMs = intervalInMs; } delay() { return delay$1(this.intervalInMs); } } /** * Note: Intentionally using function expression over arrow function expression * so that the function can be invoked with a different context. * This affects what `this` refers to. * @hidden */ const cancel = async function cancel(options = {}) { const state = this.state; const { copyId } = state; if (state.isCompleted) { return makeBlobBeginCopyFromURLPollOperation(state); } if (!copyId) { state.isCancelled = true; return makeBlobBeginCopyFromURLPollOperation(state); } // if abortCopyFromURL throws, it will bubble up to user's poller.cancelOperation call await state.blobClient.abortCopyFromURL(copyId, { abortSignal: options.abortSignal, }); state.isCancelled = true; return makeBlobBeginCopyFromURLPollOperation(state); }; /** * Note: Intentionally using function expression over arrow function expression * so that the function can be invoked with a different context. * This affects what `this` refers to. * @hidden */ const update = async function update(options = {}) { const state = this.state; const { blobClient, copySource, startCopyFromURLOptions } = state; if (!state.isStarted) { state.isStarted = true; const result = await blobClient.startCopyFromURL(copySource, startCopyFromURLOptions); // copyId is needed to abort state.copyId = result.copyId; if (result.copyStatus === "success") { state.result = result; state.isCompleted = true; } } else if (!state.isCompleted) { try { const result = await state.blobClient.getProperties({ abortSignal: options.abortSignal }); const { copyStatus, copyProgress } = result; const prevCopyProgress = state.copyProgress; if (copyProgress) { state.copyProgress = copyProgress; } if (copyStatus === "pending" && copyProgress !== prevCopyProgress && typeof options.fireProgress === "function") { // trigger in setTimeout, or swallow error? options.fireProgress(state); } else if (copyStatus === "success") { state.result = result; state.isCompleted = true; } else if (copyStatus === "failed") { state.error = new Error(`Blob copy failed with reason: "${result.copyStatusDescription || "unknown"}"`); state.isCompleted = true; } } catch (err) { state.error = err; state.isCompleted = true; } } return makeBlobBeginCopyFromURLPollOperation(state); }; /** * Note: Intentionally using function expression over arrow function expression * so that the function can be invoked with a different context. * This affects what `this` refers to. * @hidden */ const toString = function toString() { return JSON.stringify({ state: this.state }, (key, value) => { // remove blobClient from serialized state since a client can't be hydrated from this info. if (key === "blobClient") { return undefined; } return value; }); }; /** * Creates a poll operation given the provided state. * @hidden */ function makeBlobBeginCopyFromURLPollOperation(state) { return { state: { ...state }, cancel, toString, update, }; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Generate a range string. For example: * * "bytes=255-" or "bytes=0-511" * * @param iRange - */ function rangeToString(iRange) { if (iRange.offset < 0) { throw new RangeError(`Range.offset cannot be smaller than 0.`); } if (iRange.count && iRange.count <= 0) { throw new RangeError(`Range.count must be larger than 0. Leave it undefined if you want a range from offset to the end.`); } return iRange.count ? `bytes=${iRange.offset}-${iRange.offset + iRange.count - 1}` : `bytes=${iRange.offset}-`; } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // In browser, during webpack or browserify bundling, this module will be replaced by 'events' // https://github.com/Gozala/events /** * States for Batch. */ var BatchStates; (function (BatchStates) { BatchStates[BatchStates["Good"] = 0] = "Good"; BatchStates[BatchStates["Error"] = 1] = "Error"; })(BatchStates || (BatchStates = {})); /** * Batch provides basic parallel execution with concurrency limits. * Will stop execute left operations when one of the executed operation throws an error. * But Batch cannot cancel ongoing operations, you need to cancel them by yourself. */ class Batch { /** * Concurrency. Must be lager than 0. */ concurrency; /** * Number of active operations under execution. */ actives = 0; /** * Number of completed operations under execution. */ completed = 0; /** * Offset of next operation to be executed. */ offset = 0; /** * Operation array to be executed. */ operations = []; /** * States of Batch. When an error happens, state will turn into error. * Batch will stop execute left operations. */ state = BatchStates.Good; /** * A private emitter used to pass events inside this class. */ emitter; /** * Creates an instance of Batch. * @param concurrency - */ constructor(concurrency = 5) { if (concurrency < 1) { throw new RangeError("concurrency must be larger than 0"); } this.concurrency = concurrency; this.emitter = new EventEmitter(); } /** * Add a operation into queue. * * @param operation - */ addOperation(operation) { this.operations.push(async () => { try { this.actives++; await operation(); this.actives--; this.completed++; this.parallelExecute(); } catch (error) { this.emitter.emit("error", error); } }); } /** * Start execute operations in the queue. * */ async do() { if (this.operations.length === 0) { return Promise.resolve(); } this.parallelExecute(); return new Promise((resolve, reject) => { this.emitter.on("finish", resolve); this.emitter.on("error", (error) => { this.state = BatchStates.Error; reject(error); }); }); } /** * Get next operation to be executed. Return null when reaching ends. * */ nextOperation() { if (this.offset < this.operations.length) { return this.operations[this.offset++]; } return null; } /** * Start execute operations. One one the most important difference between * this method with do() is that do() wraps as an sync method. * */ parallelExecute() { if (this.state === BatchStates.Error) { return; } if (this.completed >= this.operations.length) { this.emitter.emit("finish"); return; } while (this.actives < this.concurrency) { const operation = this.nextOperation(); if (operation) { operation(); } else { return; } } } } // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * Reads a readable stream into buffer. Fill the buffer from offset to end. * * @param stream - A Node.js Readable stream * @param buffer - Buffer to be filled, length must greater than or equal to offset * @param offset - From which position in the buffer to be filled, inclusive * @param end - To which position in the buffer to be filled, exclusive * @param encoding - Encoding of the Readable stream */ async function streamToBuffer(stream, buffer, offset, end, encoding) { let pos = 0; // Position in stream const count = end - offset; // Total amount of data needed in stream return new Promise((resolve, reject) => { const timeout = setTimeout(() => reject(new Error(`The operation cannot be completed in timeout.`)), REQUEST_TIMEOUT); stream.on("readable", () => { // Already filled the requested amount; ignore any further `readable` events. if (pos >= count) { clearTimeout(timeout); resolve(); return; } // Drain all currently-buffered chunks. Required since Node.js v26, where // `stream.read()` returns one buffered chunk at a time instead of the // concatenation of all queued data (see nodejs/node#60441). let chunk; while ((chunk = stream.read()) !== null) { if (typeof chunk === "string") { chunk = Buffer.from(chunk, encoding); } // How much data needed in this chunk const chunkLength = pos + chunk.length > count ? count - pos : chunk.length; buffer.fill(chunk.slice(0, chunkLength), offset + pos, offset + pos + chunkLength); pos += chunkLength; if (pos >= count) { clearTimeout(timeout); resolve(); return; } } }); stream.on("end", () => { clearTimeout(timeout); if (pos < count) { reject(new Error(`Stream drains before getting enough data needed. Data read: ${pos}, data need: ${count}`)); } resolve(); }); stream.on("error", (msg) => { clearTimeout(timeout); reject(msg); }); }); } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * Writes the content of a readstream to a local file. Returns a Promise which is completed after the file handle is closed. * * @param rs - The read stream. * @param file - Destination file path. */ async function readStreamToLocalFile(rs, file) { return new Promise((resolve, reject) => { const ws = fs$1.createWriteStream(file); rs.on("error", (err) => { reject(err); }); ws.on("error", (err) => { reject(err); }); ws.on("close", resolve); rs.pipe(ws); }); } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * Promisified version of fs.stat(). */ const fsStat = require$$1.promisify(fs$1.stat); const fsCreateReadStream = fs$1.createReadStream; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. /** * A BlobClient represents a URL to an Azure Storage blob; the blob may be a block blob, * append blob, or page blob. */ class BlobClient extends StorageClient { /** * blobContext provided by protocol layer. */ blobContext; _name; _containerName; _versionId; _snapshot; /** * Config used in creating blob client instances. */ blobClientConfig; /** * The name of the blob. */ get name() { return this._name; } /** * The name of the storage container the blob is associated with. */ get containerName() { return this._containerName; } constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, // Legacy, no fix for eslint error without breaking. Disable it for this interface. /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/ options) { options = options || {}; let pipeline; let url; if (isPipelineLike(credentialOrPipelineOrContainerName)) { // (url: string, pipeline: Pipeline) url = urlOrConnectionString; pipeline = credentialOrPipelineOrContainerName; options = blobNameOrOptions; } else if ((credentialOrPipelineOrContainerName instanceof StorageSharedKeyCredential) || credentialOrPipelineOrContainerName instanceof AnonymousCredential || isTokenCredential(credentialOrPipelineOrContainerName)) { // (url: string, credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential, options?: StoragePipelineOptions) url = urlOrConnectionString; options = blobNameOrOptions; pipeline = newPipeline(credentialOrPipelineOrContainerName, options); } else if (!credentialOrPipelineOrContainerName && typeof credentialOrPipelineOrContainerName !== "string") { // (url: string, credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential, options?: StoragePipelineOptions) // The second parameter is undefined. Use anonymous credential. url = urlOrConnectionString; if (blobNameOrOptions && typeof blobNameOrOptions !== "string") { options = blobNameOrOptions; } pipeline = newPipeline(new AnonymousCredential(), options); } else if (credentialOrPipelineOrContainerName && typeof credentialOrPipelineOrContainerName === "string" && blobNameOrOptions && typeof blobNameOrOptions === "string") { // (connectionString: string, containerName: string, blobName: string, options?: StoragePipelineOptions) const containerName = credentialOrPipelineOrContainerName; const blobName = blobNameOrOptions; const extractedCreds = extractConnectionStringParts(urlOrConnectionString); if (extractedCreds.kind === "AccountConnString") { { const sharedKeyCredential = new StorageSharedKeyCredential(extractedCreds.accountName, extractedCreds.accountKey); url = appendToURLPath(appendToURLPath(extractedCreds.url, encodeURIComponent(containerName)), encodeURIComponent(blobName)); if (!options.proxyOptions) { options.proxyOptions = getDefaultProxySettings(extractedCreds.proxyUri); } pipeline = newPipeline(sharedKeyCredential, options); } } else if (extractedCreds.kind === "SASConnString") { url = appendToURLPath(appendToURLPath(extractedCreds.url, encodeURIComponent(containerName)), encodeURIComponent(blobName)) + "?" + extractedCreds.accountSas; pipeline = newPipeline(new AnonymousCredential(), options); } else { throw new Error("Connection string must be either an Account connection string or a SAS connection string"); } } else { throw new Error("Expecting non-empty strings for containerName and blobName parameters"); } super(url, pipeline); ({ blobName: this._name, containerName: this._containerName } = this.getBlobAndContainerNamesFromUrl()); this.blobContext = this.storageClientContext.blob; this._snapshot = getURLParameter(this.url, URLConstants.Parameters.SNAPSHOT); this._versionId = getURLParameter(this.url, URLConstants.Parameters.VERSIONID); this.blobClientConfig = options; } /** * Creates a new BlobClient object identical to the source but with the specified snapshot timestamp. * Provide "" will remove the snapshot and return a Client to the base blob. * * @param snapshot - The snapshot timestamp. * @returns A new BlobClient object identical to the source but with the specified snapshot timestamp */ withSnapshot(snapshot) { return new BlobClient(setURLParameter(this.url, URLConstants.Parameters.SNAPSHOT, snapshot.length === 0 ? undefined : snapshot), this.pipeline, this.blobClientConfig); } /** * Creates a new BlobClient object pointing to a version of this blob. * Provide "" will remove the versionId and return a Client to the base blob. * * @param versionId - The versionId. * @returns A new BlobClient object pointing to the version of this blob. */ withVersion(versionId) { return new BlobClient(setURLParameter(this.url, URLConstants.Parameters.VERSIONID, versionId.length === 0 ? undefined : versionId), this.pipeline, this.blobClientConfig); } /** * Creates a AppendBlobClient object. * */ getAppendBlobClient() { return new AppendBlobClient(this.url, this.pipeline, this.blobClientConfig); } /** * Creates a BlockBlobClient object. * */ getBlockBlobClient() { return new BlockBlobClient(this.url, this.pipeline, this.blobClientConfig); } /** * Creates a PageBlobClient object. * */ getPageBlobClient() { return new PageBlobClient(this.url, this.pipeline, this.blobClientConfig); } /** * Reads or downloads a blob from the system, including its metadata and properties. * You can also call Get Blob to read a snapshot. * * * In Node.js, data returns in a Readable stream readableStreamBody * * In browsers, data returns in a promise blobBody * * @see https://learn.microsoft.com/rest/api/storageservices/get-blob * * @param offset - From which position of the blob to download, greater than or equal to 0 * @param count - How much data to be downloaded, greater than 0. Will download to the end when undefined * @param options - Optional options to Blob Download operation. * * * Example usage (Node.js): * * ```ts snippet:ReadmeSampleDownloadBlob_Node * import { BlobServiceClient } from "@azure/storage-blob"; * import { DefaultAzureCredential } from "@azure/identity"; * * const account = ""; * const blobServiceClient = new BlobServiceClient( * `https://${account}.blob.core.windows.net`, * new DefaultAzureCredential(), * ); * * const containerName = ""; * const blobName = ""; * const containerClient = blobServiceClient.getContainerClient(containerName); * const blobClient = containerClient.getBlobClient(blobName); * * // Get blob content from position 0 to the end * // In Node.js, get downloaded data by accessing downloadBlockBlobResponse.readableStreamBody * const downloadBlockBlobResponse = await blobClient.download(); * if (downloadBlockBlobResponse.readableStreamBody) { * const downloaded = await streamToString(downloadBlockBlobResponse.readableStreamBody); * console.log(`Downloaded blob content: ${downloaded}`); * } * * async function streamToString(stream: NodeJS.ReadableStream): Promise { * const result = await new Promise>((resolve, reject) => { * const chunks: Buffer[] = []; * stream.on("data", (data) => { * chunks.push(Buffer.isBuffer(data) ? data : Buffer.from(data)); * }); * stream.on("end", () => { * resolve(Buffer.concat(chunks)); * }); * stream.on("error", reject); * }); * return result.toString(); * } * ``` * * Example usage (browser): * * ```ts snippet:ReadmeSampleDownloadBlob_Browser * import { BlobServiceClient } from "@azure/storage-blob"; * import { DefaultAzureCredential } from "@azure/identity"; * * const account = ""; * const blobServiceClient = new BlobServiceClient( * `https://${account}.blob.core.windows.net`, * new DefaultAzureCredential(), * ); * * const containerName = ""; * const blobName = ""; * const containerClient = blobServiceClient.getContainerClient(containerName); * const blobClient = containerClient.getBlobClient(blobName); * * // Get blob content from position 0 to the end * // In browsers, get downloaded data by accessing downloadBlockBlobResponse.blobBody * const downloadBlockBlobResponse = await blobClient.download(); * const blobBody = await downloadBlockBlobResponse.blobBody; * if (blobBody) { * const downloaded = await blobBody.text(); * console.log(`Downloaded blob content: ${downloaded}`); * } * ``` */ async download(offset = 0, count, options = {}) { options.conditions = options.conditions || {}; options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlobClient-download", options, async (updatedOptions) => { let contentChecksumAlgorithm = options.contentChecksumAlgorithm ?? this.blobClientConfig?.downloadContentChecksumAlgorithm; if (contentChecksumAlgorithm === undefined) { contentChecksumAlgorithm = "Customized"; } else if (contentChecksumAlgorithm === "Auto") { contentChecksumAlgorithm = "StorageCrc64"; } if (contentChecksumAlgorithm === "StorageCrc64") { await StorageCRC64Calculator.init(); } const res = assertResponse((await this.blobContext.download({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, requestOptions: { onDownloadProgress: undefined , // for Node.js, progress is reported by RetriableReadableStream }, range: offset === 0 && !count ? undefined : rangeToString({ offset, count }), rangeGetContentMD5: options.rangeGetContentMD5, rangeGetContentCRC64: options.rangeGetContentCrc64, snapshot: options.snapshot, cpkInfo: options.customerProvidedKey, tracingOptions: updatedOptions.tracingOptions, structuredBodyType: contentChecksumAlgorithm === "StorageCrc64" ? "XSM/1.0; properties=crc64" : undefined, }))); const wrappedRes = { ...res, _response: res._response, // _response is made non-enumerable objectReplicationDestinationPolicyId: res.objectReplicationPolicyId, objectReplicationSourceProperties: parseObjectReplicationRecord(res.objectReplicationRules), }; // We support retrying when download stream unexpected ends in Node.js runtime // Following code shouldn't be bundled into browser build, however some // bundlers may try to bundle following code and "FileReadResponse.ts". // In this case, "FileDownloadResponse.browser.ts" will be used as a shim of "FileDownloadResponse.ts" // The config is in package.json "browser" field if (options.maxRetryRequests === undefined || options.maxRetryRequests < 0) { // TODO: Default value or make it a required parameter? options.maxRetryRequests = DEFAULT_MAX_DOWNLOAD_RETRY_REQUESTS; } if (res.contentLength === undefined) { throw new RangeError(`File download response doesn't contain valid content length header`); } if (contentChecksumAlgorithm === "StorageCrc64" && res.structuredContentLength === undefined) { throw new RangeError(`Unexpected structured content length`); } if (!res.etag) { throw new RangeError(`File download response doesn't contain valid etag header`); } const expectedContentLength = contentChecksumAlgorithm === "StorageCrc64" ? res.structuredContentLength : res.contentLength; return new BlobDownloadResponse(wrappedRes, async (start) => { const updatedDownloadOptions = { leaseAccessConditions: options.conditions, modifiedAccessConditions: { ifMatch: options.conditions.ifMatch || res.etag, ifModifiedSince: options.conditions.ifModifiedSince, ifNoneMatch: options.conditions.ifNoneMatch, ifUnmodifiedSince: options.conditions.ifUnmodifiedSince, ifTags: options.conditions?.tagConditions, }, range: rangeToString({ count: offset + expectedContentLength - start, offset: start, }), rangeGetContentMD5: options.rangeGetContentMD5, rangeGetContentCRC64: options.rangeGetContentCrc64, snapshot: options.snapshot, cpkInfo: options.customerProvidedKey, structuredBodyType: contentChecksumAlgorithm === "StorageCrc64" ? "XSM/1.0; properties=crc64" : undefined, }; // Debug purpose only // console.log( // `Read from internal stream, range: ${ // updatedOptions.range // }, options: ${JSON.stringify(updatedOptions)}` // ); const resBody = (await this.blobContext.download({ abortSignal: options.abortSignal, ...updatedDownloadOptions, })).readableStreamBody; if (contentChecksumAlgorithm === "StorageCrc64") { return structuredMessageDecodingStream(resBody, {}); } else { return resBody; } }, offset, expectedContentLength, { maxRetryRequests: options.maxRetryRequests, onProgress: options.onProgress, }); }); } /** * Returns true if the Azure blob resource represented by this client exists; false otherwise. * * NOTE: use this function with care since an existing blob might be deleted by other clients or * applications. Vice versa new blobs might be added by other clients or applications after this * function completes. * * @param options - options to Exists operation. */ async exists(options = {}) { return tracingClient.withSpan("BlobClient-exists", options, async (updatedOptions) => { try { ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); await this.getProperties({ abortSignal: options.abortSignal, customerProvidedKey: options.customerProvidedKey, conditions: options.conditions, tracingOptions: updatedOptions.tracingOptions, }); return true; } catch (e) { if (e.statusCode === 404) { // Expected exception when checking blob existence return false; } else if (e.statusCode === 409 && (e.details.errorCode === BlobUsesCustomerSpecifiedEncryptionMsg || e.details.errorCode === BlobDoesNotUseCustomerSpecifiedEncryption)) { // Expected exception when checking blob existence return true; } throw e; } }); } /** * Returns all user-defined metadata, standard HTTP properties, and system properties * for the blob. It does not return the content of the blob. * @see https://learn.microsoft.com/rest/api/storageservices/get-blob-properties * * WARNING: The `metadata` object returned in the response will have its keys in lowercase, even if * they originally contained uppercase characters. This differs from the metadata keys returned by * the methods of {@link ContainerClient} that list blobs using the `includeMetadata` option, which * will retain their original casing. * * @param options - Optional options to Get Properties operation. */ async getProperties(options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlobClient-getProperties", options, async (updatedOptions) => { const res = assertResponse(await this.blobContext.getProperties({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, cpkInfo: options.customerProvidedKey, tracingOptions: updatedOptions.tracingOptions, })); return { ...res, _response: res._response, // _response is made non-enumerable objectReplicationDestinationPolicyId: res.objectReplicationPolicyId, objectReplicationSourceProperties: parseObjectReplicationRecord(res.objectReplicationRules), }; }); } /** * Marks the specified blob or snapshot for deletion. The blob is later deleted * during garbage collection. Note that in order to delete a blob, you must delete * all of its snapshots. You can delete both at the same time with the Delete * Blob operation. * @see https://learn.microsoft.com/rest/api/storageservices/delete-blob * * @param options - Optional options to Blob Delete operation. */ async delete(options = {}) { options.conditions = options.conditions || {}; return tracingClient.withSpan("BlobClient-delete", options, async (updatedOptions) => { return assertResponse(await this.blobContext.delete({ abortSignal: options.abortSignal, deleteSnapshots: options.deleteSnapshots, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, tracingOptions: updatedOptions.tracingOptions, accessTierIfModifiedSince: options.conditions?.accessTierIfModifiedSince, accessTierIfUnmodifiedSince: options.conditions?.accessTierIfUnmodifiedSince, })); }); } /** * Marks the specified blob or snapshot for deletion if it exists. The blob is later deleted * during garbage collection. Note that in order to delete a blob, you must delete * all of its snapshots. You can delete both at the same time with the Delete * Blob operation. * @see https://learn.microsoft.com/rest/api/storageservices/delete-blob * * @param options - Optional options to Blob Delete operation. */ async deleteIfExists(options = {}) { return tracingClient.withSpan("BlobClient-deleteIfExists", options, async (updatedOptions) => { try { const res = assertResponse(await this.delete(updatedOptions)); return { succeeded: true, ...res, _response: res._response, // _response is made non-enumerable }; } catch (e) { if (e.details?.errorCode === "BlobNotFound") { return { succeeded: false, ...e.response?.parsedHeaders, _response: e.response, }; } throw e; } }); } /** * Restores the contents and metadata of soft deleted blob and any associated * soft deleted snapshots. Undelete Blob is supported only on version 2017-07-29 * or later. * @see https://learn.microsoft.com/rest/api/storageservices/undelete-blob * * @param options - Optional options to Blob Undelete operation. */ async undelete(options = {}) { return tracingClient.withSpan("BlobClient-undelete", options, async (updatedOptions) => { return assertResponse(await this.blobContext.undelete({ abortSignal: options.abortSignal, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Sets system properties on the blob. * * If no value provided, or no value provided for the specified blob HTTP headers, * these blob HTTP headers without a value will be cleared. * @see https://learn.microsoft.com/rest/api/storageservices/set-blob-properties * * @param blobHTTPHeaders - If no value provided, or no value provided for * the specified blob HTTP headers, these blob HTTP * headers without a value will be cleared. * A common header to set is `blobContentType` * enabling the browser to provide functionality * based on file type. * @param options - Optional options to Blob Set HTTP Headers operation. */ async setHTTPHeaders(blobHTTPHeaders, options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlobClient-setHTTPHeaders", options, async (updatedOptions) => { return assertResponse(await this.blobContext.setHttpHeaders({ abortSignal: options.abortSignal, blobHttpHeaders: blobHTTPHeaders, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, // cpkInfo: options.customerProvidedKey, // CPK is not included in Swagger, should change this back when this issue is fixed in Swagger. tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Sets user-defined metadata for the specified blob as one or more name-value pairs. * * If no option provided, or no metadata defined in the parameter, the blob * metadata will be removed. * @see https://learn.microsoft.com/rest/api/storageservices/set-blob-metadata * * @param metadata - Replace existing metadata with this value. * If no value provided the existing metadata will be removed. * @param options - Optional options to Set Metadata operation. */ async setMetadata(metadata, options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlobClient-setMetadata", options, async (updatedOptions) => { return assertResponse(await this.blobContext.setMetadata({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, metadata, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Sets tags on the underlying blob. * A blob can have up to 10 tags. Tag keys must be between 1 and 128 characters. Tag values must be between 0 and 256 characters. * Valid tag key and value characters include lower and upper case letters, digits (0-9), * space (' '), plus ('+'), minus ('-'), period ('.'), foward slash ('/'), colon (':'), equals ('='), and underscore ('_'). * * @param tags - * @param options - */ async setTags(tags, options = {}) { return tracingClient.withSpan("BlobClient-setTags", options, async (updatedOptions) => { return assertResponse(await this.blobContext.setTags({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, blobModifiedAccessConditions: options.conditions, tracingOptions: updatedOptions.tracingOptions, tags: toBlobTags(tags), })); }); } /** * Gets the tags associated with the underlying blob. * * @param options - */ async getTags(options = {}) { return tracingClient.withSpan("BlobClient-getTags", options, async (updatedOptions) => { const response = assertResponse(await this.blobContext.getTags({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, blobModifiedAccessConditions: options.conditions, tracingOptions: updatedOptions.tracingOptions, })); const wrappedResponse = { ...response, _response: response._response, // _response is made non-enumerable tags: toTags({ blobTagSet: response.blobTagSet }) || {}, }; return wrappedResponse; }); } /** * Get a {@link BlobLeaseClient} that manages leases on the blob. * * @param proposeLeaseId - Initial proposed lease Id. * @returns A new BlobLeaseClient object for managing leases on the blob. */ getBlobLeaseClient(proposeLeaseId) { return new BlobLeaseClient(this, proposeLeaseId); } /** * Creates a read-only snapshot of a blob. * @see https://learn.microsoft.com/rest/api/storageservices/snapshot-blob * * @param options - Optional options to the Blob Create Snapshot operation. */ async createSnapshot(options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlobClient-createSnapshot", options, async (updatedOptions) => { return assertResponse(await this.blobContext.createSnapshot({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, metadata: options.metadata, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Asynchronously copies a blob to a destination within the storage account. * This method returns a long running operation poller that allows you to wait * indefinitely until the copy is completed. * You can also cancel a copy before it is completed by calling `cancelOperation` on the poller. * Note that the onProgress callback will not be invoked if the operation completes in the first * request, and attempting to cancel a completed copy will result in an error being thrown. * * In version 2012-02-12 and later, the source for a Copy Blob operation can be * a committed blob in any Azure storage account. * Beginning with version 2015-02-21, the source for a Copy Blob operation can be * an Azure file in any Azure storage account. * Only storage accounts created on or after June 7th, 2012 allow the Copy Blob * operation to copy from another storage account. * @see https://learn.microsoft.com/rest/api/storageservices/copy-blob * * ```ts snippet:ClientsBeginCopyFromURL * import { BlobServiceClient } from "@azure/storage-blob"; * import { DefaultAzureCredential } from "@azure/identity"; * * const account = ""; * const blobServiceClient = new BlobServiceClient( * `https://${account}.blob.core.windows.net`, * new DefaultAzureCredential(), * ); * * const containerName = ""; * const blobName = ""; * const containerClient = blobServiceClient.getContainerClient(containerName); * const blobClient = containerClient.getBlobClient(blobName); * * // Example using automatic polling * const automaticCopyPoller = await blobClient.beginCopyFromURL("url"); * const automaticResult = await automaticCopyPoller.pollUntilDone(); * * // Example using manual polling * const manualCopyPoller = await blobClient.beginCopyFromURL("url"); * while (!manualCopyPoller.isDone()) { * await manualCopyPoller.poll(); * } * const manualResult = manualCopyPoller.getResult(); * * // Example using progress updates * const progressUpdatesCopyPoller = await blobClient.beginCopyFromURL("url", { * onProgress(state) { * console.log(`Progress: ${state.copyProgress}`); * }, * }); * const progressUpdatesResult = await progressUpdatesCopyPoller.pollUntilDone(); * * // Example using a changing polling interval (default 15 seconds) * const pollingIntervalCopyPoller = await blobClient.beginCopyFromURL("url", { * intervalInMs: 1000, // poll blob every 1 second for copy progress * }); * const pollingIntervalResult = await pollingIntervalCopyPoller.pollUntilDone(); * * // Example using copy cancellation: * const cancelCopyPoller = await blobClient.beginCopyFromURL("url"); * // cancel operation after starting it. * try { * await cancelCopyPoller.cancelOperation(); * // calls to get the result now throw PollerCancelledError * cancelCopyPoller.getResult(); * } catch (err: any) { * if (err.name === "PollerCancelledError") { * console.log("The copy was cancelled."); * } * } * ``` * * @param copySource - url to the source Azure Blob/File. * @param options - Optional options to the Blob Start Copy From URL operation. */ async beginCopyFromURL(copySource, options = {}) { const client = { abortCopyFromURL: (...args) => this.abortCopyFromURL(...args), getProperties: (...args) => this.getProperties(...args), startCopyFromURL: (...args) => this.startCopyFromURL(...args), }; const poller = new BlobBeginCopyFromUrlPoller({ blobClient: client, copySource, intervalInMs: options.intervalInMs, onProgress: options.onProgress, resumeFrom: options.resumeFrom, startCopyFromURLOptions: options, }); // Trigger the startCopyFromURL call by calling poll. // Any errors from this method should be surfaced to the user. await poller.poll(); return poller; } /** * Aborts a pending asynchronous Copy Blob operation, and leaves a destination blob with zero * length and full metadata. Version 2012-02-12 and newer. * @see https://learn.microsoft.com/rest/api/storageservices/abort-copy-blob * * @param copyId - Id of the Copy From URL operation. * @param options - Optional options to the Blob Abort Copy From URL operation. */ async abortCopyFromURL(copyId, options = {}) { return tracingClient.withSpan("BlobClient-abortCopyFromURL", options, async (updatedOptions) => { return assertResponse(await this.blobContext.abortCopyFromURL(copyId, { abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * The synchronous Copy From URL operation copies a blob or an internet resource to a new blob. It will not * return a response until the copy is complete. * @see https://learn.microsoft.com/rest/api/storageservices/copy-blob-from-url * * @param copySource - The source URL to copy from, Shared Access Signature(SAS) maybe needed for authentication * @param options - */ async syncCopyFromURL(copySource, options = {}) { options.conditions = options.conditions || {}; options.sourceConditions = options.sourceConditions || {}; return tracingClient.withSpan("BlobClient-syncCopyFromURL", options, async (updatedOptions) => { return assertResponse(await this.blobContext.copyFromURL(copySource, { abortSignal: options.abortSignal, metadata: options.metadata, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, sourceModifiedAccessConditions: { sourceIfMatch: options.sourceConditions?.ifMatch, sourceIfModifiedSince: options.sourceConditions?.ifModifiedSince, sourceIfNoneMatch: options.sourceConditions?.ifNoneMatch, sourceIfUnmodifiedSince: options.sourceConditions?.ifUnmodifiedSince, }, sourceContentMD5: options.sourceContentMD5, copySourceAuthorization: httpAuthorizationToString(options.sourceAuthorization), tier: toAccessTier(options.tier), blobTagsString: toBlobTagsString(options.tags), immutabilityPolicyExpiry: options.immutabilityPolicy?.expiriesOn, immutabilityPolicyMode: options.immutabilityPolicy?.policyMode, legalHold: options.legalHold, encryptionScope: options.encryptionScope, copySourceTags: options.copySourceTags, fileRequestIntent: options.sourceShareTokenIntent, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Sets the tier on a blob. The operation is allowed on a page blob in a premium * storage account and on a block blob in a blob storage account (locally redundant * storage only). A premium page blob's tier determines the allowed size, IOPS, * and bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive * storage type. This operation does not update the blob's ETag. * @see https://learn.microsoft.com/rest/api/storageservices/set-blob-tier * * @param tier - The tier to be set on the blob. Valid values are Hot, Cool, or Archive. * @param options - Optional options to the Blob Set Tier operation. */ async setAccessTier(tier, options = {}) { return tracingClient.withSpan("BlobClient-setAccessTier", options, async (updatedOptions) => { return assertResponse(await this.blobContext.setTier(toAccessTier(tier), { abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, rehydratePriority: options.rehydratePriority, tracingOptions: updatedOptions.tracingOptions, })); }); } async downloadToBuffer(param1, param2, param3, param4 = {}) { let buffer; let offset = 0; let count = 0; let options = param4; if (param1 instanceof Buffer) { buffer = param1; offset = param2 || 0; count = typeof param3 === "number" ? param3 : 0; } else { offset = typeof param1 === "number" ? param1 : 0; count = typeof param2 === "number" ? param2 : 0; options = param3 || {}; } let blockSize = options.blockSize ?? 0; if (blockSize < 0) { throw new RangeError("blockSize option must be >= 0"); } if (blockSize === 0) { blockSize = DEFAULT_BLOB_DOWNLOAD_BLOCK_BYTES; } if (offset < 0) { throw new RangeError("offset option must be >= 0"); } if (count && count <= 0) { throw new RangeError("count option must be greater than 0"); } if (!options.conditions) { options.conditions = {}; } return tracingClient.withSpan("BlobClient-downloadToBuffer", options, async (updatedOptions) => { // Customer doesn't specify length, get it if (!count) { const response = await this.getProperties({ ...options, tracingOptions: updatedOptions.tracingOptions, }); count = response.contentLength - offset; if (count < 0) { throw new RangeError(`offset ${offset} shouldn't be larger than blob size ${response.contentLength}`); } } // Allocate the buffer of size = count if the buffer is not provided if (!buffer) { try { buffer = Buffer.alloc(count); } catch (error) { throw new Error(`Unable to allocate the buffer of size: ${count}(in bytes). Please try passing your own buffer to the "downloadToBuffer" method or try using other methods like "download" or "downloadToFile".\t ${error.message}`); } } if (buffer.length < count) { throw new RangeError(`The buffer's size should be equal to or larger than the request count of bytes: ${count}`); } let transferProgress = 0; const batch = new Batch(options.concurrency); for (let off = offset; off < offset + count; off = off + blockSize) { batch.addOperation(async () => { // Exclusive chunk end position let chunkEnd = offset + count; if (off + blockSize < chunkEnd) { chunkEnd = off + blockSize; } const response = await this.download(off, chunkEnd - off, { abortSignal: options.abortSignal, conditions: options.conditions, maxRetryRequests: options.maxRetryRequestsPerBlock, customerProvidedKey: options.customerProvidedKey, contentChecksumAlgorithm: options.contentChecksumAlgorithm, tracingOptions: updatedOptions.tracingOptions, }); const stream = response.readableStreamBody; await streamToBuffer(stream, buffer, off - offset, chunkEnd - offset); // Update progress after block is downloaded, in case of block trying // Could provide finer grained progress updating inside HTTP requests, // only if convenience layer download try is enabled transferProgress += chunkEnd - off; if (options.onProgress) { options.onProgress({ loadedBytes: transferProgress }); } }); } await batch.do(); return buffer; }); } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * Downloads an Azure Blob to a local file. * Fails if the the given file path already exits. * Offset and count are optional, pass 0 and undefined respectively to download the entire blob. * * @param filePath - * @param offset - From which position of the block blob to download. * @param count - How much data to be downloaded. Will download to the end when passing undefined. * @param options - Options to Blob download options. * @returns The response data for blob download operation, * but with readableStreamBody set to undefined since its * content is already read and written into a local file * at the specified path. */ async downloadToFile(filePath, offset = 0, count, options = {}) { return tracingClient.withSpan("BlobClient-downloadToFile", options, async (updatedOptions) => { const response = await this.download(offset, count, { ...options, tracingOptions: updatedOptions.tracingOptions, }); if (response.readableStreamBody) { await readStreamToLocalFile(response.readableStreamBody, filePath); } // The stream is no longer accessible so setting it to undefined. response.blobDownloadStream = undefined; return response; }); } getBlobAndContainerNamesFromUrl() { let containerName; let blobName; try { // URL may look like the following // "https://myaccount.blob.core.windows.net/mycontainer/blob?sasString"; // "https://myaccount.blob.core.windows.net/mycontainer/blob"; // "https://myaccount.blob.core.windows.net/mycontainer/blob/a.txt?sasString"; // "https://myaccount.blob.core.windows.net/mycontainer/blob/a.txt"; // IPv4/IPv6 address hosts, Endpoints - `http://127.0.0.1:10000/devstoreaccount1/containername/blob` // http://localhost:10001/devstoreaccount1/containername/blob const parsedUrl = new URL(this.url); if (parsedUrl.host.split(".")[1] === "blob") { // "https://myaccount.blob.core.windows.net/containername/blob". // .getPath() -> /containername/blob const pathComponents = parsedUrl.pathname.match("/([^/]*)(/(.*))?"); containerName = pathComponents[1]; blobName = pathComponents[3]; } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/containername/blob // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/containername/blob // .getPath() -> /devstoreaccount1/containername/blob const pathComponents = parsedUrl.pathname.match("/([^/]*)/([^/]*)(/(.*))?"); containerName = pathComponents[2]; blobName = pathComponents[4]; } else { // "https://customdomain.com/containername/blob". // .getPath() -> /containername/blob const pathComponents = parsedUrl.pathname.match("/([^/]*)(/(.*))?"); containerName = pathComponents[1]; blobName = pathComponents[3]; } // decode the encoded blobName, containerName - to get all the special characters that might be present in them containerName = decodeURIComponent(containerName); blobName = decodeURIComponent(blobName); // Azure Storage Server will replace "\" with "/" in the blob names // doing the same in the SDK side so that the user doesn't have to replace "\" instances in the blobName blobName = blobName.replace(/\\/g, "/"); if (!containerName) { throw new Error("Provided containerName is invalid."); } return { blobName, containerName }; } catch (error) { throw new Error("Unable to extract blobName and containerName with provided information."); } } /** * Asynchronously copies a blob to a destination within the storage account. * In version 2012-02-12 and later, the source for a Copy Blob operation can be * a committed blob in any Azure storage account. * Beginning with version 2015-02-21, the source for a Copy Blob operation can be * an Azure file in any Azure storage account. * Only storage accounts created on or after June 7th, 2012 allow the Copy Blob * operation to copy from another storage account. * @see https://learn.microsoft.com/rest/api/storageservices/copy-blob * * @param copySource - url to the source Azure Blob/File. * @param options - Optional options to the Blob Start Copy From URL operation. */ async startCopyFromURL(copySource, options = {}) { return tracingClient.withSpan("BlobClient-startCopyFromURL", options, async (updatedOptions) => { options.conditions = options.conditions || {}; options.sourceConditions = options.sourceConditions || {}; return assertResponse(await this.blobContext.startCopyFromURL(copySource, { abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, metadata: options.metadata, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, sourceModifiedAccessConditions: { sourceIfMatch: options.sourceConditions.ifMatch, sourceIfModifiedSince: options.sourceConditions.ifModifiedSince, sourceIfNoneMatch: options.sourceConditions.ifNoneMatch, sourceIfUnmodifiedSince: options.sourceConditions.ifUnmodifiedSince, sourceIfTags: options.sourceConditions.tagConditions, }, immutabilityPolicyExpiry: options.immutabilityPolicy?.expiriesOn, immutabilityPolicyMode: options.immutabilityPolicy?.policyMode, legalHold: options.legalHold, rehydratePriority: options.rehydratePriority, tier: toAccessTier(options.tier), blobTagsString: toBlobTagsString(options.tags), sealBlob: options.sealBlob, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Only available for BlobClient constructed with a shared key credential. * * Generates a Blob Service Shared Access Signature (SAS) URI based on the client properties * and parameters passed in. The SAS is signed by the shared key credential of the client. * * @see https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas * * @param options - Optional parameters. * @returns The SAS URI consisting of the URI to the resource represented by this client, followed by the generated SAS token. */ generateSasUrl(options) { return new Promise((resolve) => { if (!(this.credential instanceof StorageSharedKeyCredential)) { throw new RangeError("Can only generate the SAS when the client is initialized with a shared key credential"); } const sas = generateBlobSASQueryParameters({ containerName: this._containerName, blobName: this._name, snapshotTime: this._snapshot, versionId: this._versionId, ...options, }, this.credential).toString(); resolve(appendToURLQuery(this.url, sas)); }); } /** * Only available for BlobClient constructed with a shared key credential. * * Generates string to sign for a Blob Service Shared Access Signature (SAS) URI based on * the client properties and parameters passed in. The SAS is signed by the shared key credential of the client. * * @see https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas * * @param options - Optional parameters. * @returns The SAS URI consisting of the URI to the resource represented by this client, followed by the generated SAS token. */ /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/ generateSasStringToSign(options) { if (!(this.credential instanceof StorageSharedKeyCredential)) { throw new RangeError("Can only generate the SAS when the client is initialized with a shared key credential"); } return generateBlobSASQueryParametersInternal({ containerName: this._containerName, blobName: this._name, snapshotTime: this._snapshot, versionId: this._versionId, ...options, }, this.credential).stringToSign; } /** * * Generates a Blob Service Shared Access Signature (SAS) URI based on * the client properties and parameters passed in. The SAS is signed by the input user delegation key. * * @see https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas * * @param options - Optional parameters. * @param userDelegationKey - Return value of `blobServiceClient.getUserDelegationKey()` * @returns The SAS URI consisting of the URI to the resource represented by this client, followed by the generated SAS token. */ generateUserDelegationSasUrl(options, userDelegationKey) { return new Promise((resolve) => { const sas = generateBlobSASQueryParameters({ containerName: this._containerName, blobName: this._name, snapshotTime: this._snapshot, versionId: this._versionId, ...options, }, userDelegationKey, this.accountName).toString(); resolve(appendToURLQuery(this.url, sas)); }); } /** * Only available for BlobClient constructed with a shared key credential. * * Generates string to sign for a Blob Service Shared Access Signature (SAS) URI based on * the client properties and parameters passed in. The SAS is signed by the input user delegation key. * * @see https://learn.microsoft.com/rest/api/storageservices/constructing-a-service-sas * * @param options - Optional parameters. * @param userDelegationKey - Return value of `blobServiceClient.getUserDelegationKey()` * @returns The SAS URI consisting of the URI to the resource represented by this client, followed by the generated SAS token. */ generateUserDelegationSasStringToSign(options, userDelegationKey) { return generateBlobSASQueryParametersInternal({ containerName: this._containerName, blobName: this._name, snapshotTime: this._snapshot, versionId: this._versionId, ...options, }, userDelegationKey, this.accountName).stringToSign; } /** * Delete the immutablility policy on the blob. * * @param options - Optional options to delete immutability policy on the blob. */ async deleteImmutabilityPolicy(options = {}) { return tracingClient.withSpan("BlobClient-deleteImmutabilityPolicy", options, async (updatedOptions) => { return assertResponse(await this.blobContext.deleteImmutabilityPolicy({ tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Set immutability policy on the blob. * * @param options - Optional options to set immutability policy on the blob. */ async setImmutabilityPolicy(immutabilityPolicy, options = {}) { return tracingClient.withSpan("BlobClient-setImmutabilityPolicy", options, async (updatedOptions) => { return assertResponse(await this.blobContext.setImmutabilityPolicy({ immutabilityPolicyExpiry: immutabilityPolicy.expiriesOn, immutabilityPolicyMode: immutabilityPolicy.policyMode, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Set legal hold on the blob. * * @param options - Optional options to set legal hold on the blob. */ async setLegalHold(legalHoldEnabled, options = {}) { return tracingClient.withSpan("BlobClient-setLegalHold", options, async (updatedOptions) => { return assertResponse(await this.blobContext.setLegalHold(legalHoldEnabled, { tracingOptions: updatedOptions.tracingOptions, })); }); } /** * The Get Account Information operation returns the sku name and account kind * for the specified account. * The Get Account Information operation is available on service versions beginning * with version 2018-03-28. * @see https://learn.microsoft.com/rest/api/storageservices/get-account-information * * @param options - Options to the Service Get Account Info operation. * @returns Response data for the Service Get Account Info operation. */ async getAccountInfo(options = {}) { return tracingClient.withSpan("BlobClient-getAccountInfo", options, async (updatedOptions) => { return assertResponse(await this.blobContext.getAccountInfo({ abortSignal: options.abortSignal, tracingOptions: updatedOptions.tracingOptions, })); }); } } /** * AppendBlobClient defines a set of operations applicable to append blobs. */ class AppendBlobClient extends BlobClient { /** * appendBlobsContext provided by protocol layer. */ appendBlobContext; constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, // Legacy, no fix for eslint error without breaking. Disable it for this interface. /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/ options) { // In TypeScript we cannot simply pass all parameters to super() like below so have to duplicate the code instead. // super(s, credentialOrPipelineOrContainerNameOrOptions, blobNameOrOptions, options); let pipeline; let url; options = options || {}; if (isPipelineLike(credentialOrPipelineOrContainerName)) { // (url: string, pipeline: Pipeline) url = urlOrConnectionString; pipeline = credentialOrPipelineOrContainerName; options = blobNameOrOptions; } else if ((credentialOrPipelineOrContainerName instanceof StorageSharedKeyCredential) || credentialOrPipelineOrContainerName instanceof AnonymousCredential || isTokenCredential(credentialOrPipelineOrContainerName)) { // (url: string, credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential, options?: StoragePipelineOptions) url = urlOrConnectionString; url = urlOrConnectionString; options = blobNameOrOptions; pipeline = newPipeline(credentialOrPipelineOrContainerName, options); } else if (!credentialOrPipelineOrContainerName && typeof credentialOrPipelineOrContainerName !== "string") { // (url: string, credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential, options?: StoragePipelineOptions) url = urlOrConnectionString; options = blobNameOrOptions; // The second parameter is undefined. Use anonymous credential. pipeline = newPipeline(new AnonymousCredential(), options); } else if (credentialOrPipelineOrContainerName && typeof credentialOrPipelineOrContainerName === "string" && blobNameOrOptions && typeof blobNameOrOptions === "string") { // (connectionString: string, containerName: string, blobName: string, options?: StoragePipelineOptions) const containerName = credentialOrPipelineOrContainerName; const blobName = blobNameOrOptions; const extractedCreds = extractConnectionStringParts(urlOrConnectionString); if (extractedCreds.kind === "AccountConnString") { { const sharedKeyCredential = new StorageSharedKeyCredential(extractedCreds.accountName, extractedCreds.accountKey); url = appendToURLPath(appendToURLPath(extractedCreds.url, encodeURIComponent(containerName)), encodeURIComponent(blobName)); if (!options.proxyOptions) { options.proxyOptions = getDefaultProxySettings(extractedCreds.proxyUri); } pipeline = newPipeline(sharedKeyCredential, options); } } else if (extractedCreds.kind === "SASConnString") { url = appendToURLPath(appendToURLPath(extractedCreds.url, encodeURIComponent(containerName)), encodeURIComponent(blobName)) + "?" + extractedCreds.accountSas; pipeline = newPipeline(new AnonymousCredential(), options); } else { throw new Error("Connection string must be either an Account connection string or a SAS connection string"); } } else { throw new Error("Expecting non-empty strings for containerName and blobName parameters"); } super(url, pipeline); this.appendBlobContext = this.storageClientContext.appendBlob; this.blobClientConfig = options; } /** * Creates a new AppendBlobClient object identical to the source but with the * specified snapshot timestamp. * Provide "" will remove the snapshot and return a Client to the base blob. * * @param snapshot - The snapshot timestamp. * @returns A new AppendBlobClient object identical to the source but with the specified snapshot timestamp. */ withSnapshot(snapshot) { return new AppendBlobClient(setURLParameter(this.url, URLConstants.Parameters.SNAPSHOT, snapshot.length === 0 ? undefined : snapshot), this.pipeline, this.blobClientConfig); } /** * Creates a 0-length append blob. Call AppendBlock to append data to an append blob. * @see https://learn.microsoft.com/rest/api/storageservices/put-blob * * @param options - Options to the Append Block Create operation. * * * Example usage: * * ```ts snippet:ClientsCreateAppendBlob * import { BlobServiceClient } from "@azure/storage-blob"; * import { DefaultAzureCredential } from "@azure/identity"; * * const account = ""; * const blobServiceClient = new BlobServiceClient( * `https://${account}.blob.core.windows.net`, * new DefaultAzureCredential(), * ); * * const containerName = ""; * const blobName = ""; * const containerClient = blobServiceClient.getContainerClient(containerName); * * const appendBlobClient = containerClient.getAppendBlobClient(blobName); * await appendBlobClient.create(); * ``` */ async create(options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("AppendBlobClient-create", options, async (updatedOptions) => { return assertResponse(await this.appendBlobContext.create(0, { abortSignal: options.abortSignal, blobHttpHeaders: options.blobHTTPHeaders, leaseAccessConditions: options.conditions, metadata: options.metadata, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, immutabilityPolicyExpiry: options.immutabilityPolicy?.expiriesOn, immutabilityPolicyMode: options.immutabilityPolicy?.policyMode, legalHold: options.legalHold, blobTagsString: toBlobTagsString(options.tags), tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Creates a 0-length append blob. Call AppendBlock to append data to an append blob. * If the blob with the same name already exists, the content of the existing blob will remain unchanged. * @see https://learn.microsoft.com/rest/api/storageservices/put-blob * * @param options - */ async createIfNotExists(options = {}) { const conditions = { ifNoneMatch: ETagAny }; return tracingClient.withSpan("AppendBlobClient-createIfNotExists", options, async (updatedOptions) => { try { const res = assertResponse(await this.create({ ...updatedOptions, conditions, })); return { succeeded: true, ...res, _response: res._response, // _response is made non-enumerable }; } catch (e) { if (e.details?.errorCode === "BlobAlreadyExists") { return { succeeded: false, ...e.response?.parsedHeaders, _response: e.response, }; } throw e; } }); } /** * Seals the append blob, making it read only. * * @param options - */ async seal(options = {}) { options.conditions = options.conditions || {}; return tracingClient.withSpan("AppendBlobClient-seal", options, async (updatedOptions) => { return assertResponse(await this.appendBlobContext.seal({ abortSignal: options.abortSignal, appendPositionAccessConditions: options.conditions, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Commits a new block of data to the end of the existing append blob. * @see https://learn.microsoft.com/rest/api/storageservices/append-block * * @param body - Data to be appended. * @param contentLength - Length of the body in bytes. * @param options - Options to the Append Block operation. * * * Example usage: * * ```ts snippet:ClientsAppendBlock * import { BlobServiceClient } from "@azure/storage-blob"; * import { DefaultAzureCredential } from "@azure/identity"; * * const account = ""; * const blobServiceClient = new BlobServiceClient( * `https://${account}.blob.core.windows.net`, * new DefaultAzureCredential(), * ); * * const containerName = ""; * const blobName = ""; * const containerClient = blobServiceClient.getContainerClient(containerName); * * const content = "Hello World!"; * * // Create a new append blob and append data to the blob. * const newAppendBlobClient = containerClient.getAppendBlobClient(blobName); * await newAppendBlobClient.create(); * await newAppendBlobClient.appendBlock(content, content.length); * * // Append data to an existing append blob. * const existingAppendBlobClient = containerClient.getAppendBlobClient(blobName); * await existingAppendBlobClient.appendBlock(content, content.length); * ``` */ async appendBlock(body, contentLength, options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("AppendBlobClient-appendBlock", options, async (updatedOptions) => { const parameters = { abortSignal: options.abortSignal, appendPositionAccessConditions: options.conditions, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, requestOptions: { onUploadProgress: options.onProgress, }, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, tracingOptions: updatedOptions.tracingOptions, }; const uploadBodyParameters = await setUploadChecksumParameters(body, contentLength, parameters, options, this.blobClientConfig?.uploadContentChecksumAlgorithm); return assertResponse(await this.appendBlobContext.appendBlock(uploadBodyParameters.contentLength, uploadBodyParameters.body, parameters)); }); } /** * The Append Block operation commits a new block of data to the end of an existing append blob * where the contents are read from a source url. * @see https://learn.microsoft.com/rest/api/storageservices/append-block-from-url * * @param sourceURL - * The url to the blob that will be the source of the copy. A source blob in the same storage account can * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob * must either be public or must be authenticated via a shared access signature. If the source blob is * public, no authentication is required to perform the operation. * @param sourceOffset - Offset in source to be appended * @param count - Number of bytes to be appended as a block * @param options - */ async appendBlockFromURL(sourceURL, sourceOffset, count, options = {}) { options.conditions = options.conditions || {}; options.sourceConditions = options.sourceConditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("AppendBlobClient-appendBlockFromURL", options, async (updatedOptions) => { return assertResponse(await this.appendBlobContext.appendBlockFromUrl(sourceURL, 0, { abortSignal: options.abortSignal, sourceRange: rangeToString({ offset: sourceOffset, count }), sourceContentMD5: options.sourceContentMD5, sourceContentCrc64: options.sourceContentCrc64, leaseAccessConditions: options.conditions, appendPositionAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, sourceModifiedAccessConditions: { sourceIfMatch: options.sourceConditions?.ifMatch, sourceIfModifiedSince: options.sourceConditions?.ifModifiedSince, sourceIfNoneMatch: options.sourceConditions?.ifNoneMatch, sourceIfUnmodifiedSince: options.sourceConditions?.ifUnmodifiedSince, }, copySourceAuthorization: httpAuthorizationToString(options.sourceAuthorization), cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, fileRequestIntent: options.sourceShareTokenIntent, tracingOptions: updatedOptions.tracingOptions, sourceCpkInfo: { sourceEncryptionKey: options.sourceCustomerProvidedKey?.encryptionKey, sourceEncryptionAlgorithm: options.sourceCustomerProvidedKey?.encryptionAlgorithm, sourceEncryptionKeySha256: options.sourceCustomerProvidedKey?.encryptionKeySha256, }, })); }); } } /** * BlockBlobClient defines a set of operations applicable to block blobs. */ class BlockBlobClient extends BlobClient { /** * blobContext provided by protocol layer. * * Note. Ideally BlobClient should set BlobClient.blobContext to protected. However, API * extractor has issue blocking that. Here we redecelare _blobContext in BlockBlobClient. */ _blobContext; /** * blockBlobContext provided by protocol layer. */ blockBlobContext; constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, // Legacy, no fix for eslint error without breaking. Disable it for this interface. /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/ options) { // In TypeScript we cannot simply pass all parameters to super() like below so have to duplicate the code instead. // super(s, credentialOrPipelineOrContainerNameOrOptions, blobNameOrOptions, options); let pipeline; let url; options = options || {}; if (isPipelineLike(credentialOrPipelineOrContainerName)) { // (url: string, pipeline: Pipeline) url = urlOrConnectionString; pipeline = credentialOrPipelineOrContainerName; options = blobNameOrOptions; } else if ((credentialOrPipelineOrContainerName instanceof StorageSharedKeyCredential) || credentialOrPipelineOrContainerName instanceof AnonymousCredential || isTokenCredential(credentialOrPipelineOrContainerName)) { // (url: string, credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential, options?: StoragePipelineOptions) url = urlOrConnectionString; options = blobNameOrOptions; pipeline = newPipeline(credentialOrPipelineOrContainerName, options); } else if (!credentialOrPipelineOrContainerName && typeof credentialOrPipelineOrContainerName !== "string") { // (url: string, credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential, options?: StoragePipelineOptions) // The second parameter is undefined. Use anonymous credential. url = urlOrConnectionString; if (blobNameOrOptions && typeof blobNameOrOptions !== "string") { options = blobNameOrOptions; } pipeline = newPipeline(new AnonymousCredential(), options); } else if (credentialOrPipelineOrContainerName && typeof credentialOrPipelineOrContainerName === "string" && blobNameOrOptions && typeof blobNameOrOptions === "string") { // (connectionString: string, containerName: string, blobName: string, options?: StoragePipelineOptions) const containerName = credentialOrPipelineOrContainerName; const blobName = blobNameOrOptions; const extractedCreds = extractConnectionStringParts(urlOrConnectionString); if (extractedCreds.kind === "AccountConnString") { { const sharedKeyCredential = new StorageSharedKeyCredential(extractedCreds.accountName, extractedCreds.accountKey); url = appendToURLPath(appendToURLPath(extractedCreds.url, encodeURIComponent(containerName)), encodeURIComponent(blobName)); if (!options.proxyOptions) { options.proxyOptions = getDefaultProxySettings(extractedCreds.proxyUri); } pipeline = newPipeline(sharedKeyCredential, options); } } else if (extractedCreds.kind === "SASConnString") { url = appendToURLPath(appendToURLPath(extractedCreds.url, encodeURIComponent(containerName)), encodeURIComponent(blobName)) + "?" + extractedCreds.accountSas; pipeline = newPipeline(new AnonymousCredential(), options); } else { throw new Error("Connection string must be either an Account connection string or a SAS connection string"); } } else { throw new Error("Expecting non-empty strings for containerName and blobName parameters"); } super(url, pipeline); this.blockBlobContext = this.storageClientContext.blockBlob; this._blobContext = this.storageClientContext.blob; this.blobClientConfig = options; } /** * Creates a new BlockBlobClient object identical to the source but with the * specified snapshot timestamp. * Provide "" will remove the snapshot and return a URL to the base blob. * * @param snapshot - The snapshot timestamp. * @returns A new BlockBlobClient object identical to the source but with the specified snapshot timestamp. */ withSnapshot(snapshot) { return new BlockBlobClient(setURLParameter(this.url, URLConstants.Parameters.SNAPSHOT, snapshot.length === 0 ? undefined : snapshot), this.pipeline, this.blobClientConfig); } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * Quick query for a JSON or CSV formatted blob. * * Example usage (Node.js): * * ```ts snippet:ClientsQuery * import { BlobServiceClient } from "@azure/storage-blob"; * import { DefaultAzureCredential } from "@azure/identity"; * * const account = ""; * const blobServiceClient = new BlobServiceClient( * `https://${account}.blob.core.windows.net`, * new DefaultAzureCredential(), * ); * * const containerName = ""; * const blobName = ""; * const containerClient = blobServiceClient.getContainerClient(containerName); * const blockBlobClient = containerClient.getBlockBlobClient(blobName); * * // Query and convert a blob to a string * const queryBlockBlobResponse = await blockBlobClient.query("select from BlobStorage"); * if (queryBlockBlobResponse.readableStreamBody) { * const downloadedBuffer = await streamToBuffer(queryBlockBlobResponse.readableStreamBody); * const downloaded = downloadedBuffer.toString(); * console.log(`Query blob content: ${downloaded}`); * } * * async function streamToBuffer(readableStream: NodeJS.ReadableStream): Promise { * return new Promise((resolve, reject) => { * const chunks: Buffer[] = []; * readableStream.on("data", (data) => { * chunks.push(data instanceof Buffer ? data : Buffer.from(data)); * }); * readableStream.on("end", () => { * resolve(Buffer.concat(chunks)); * }); * readableStream.on("error", reject); * }); * } * ``` * * @param query - * @param options - */ async query(query, options = {}) { ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlockBlobClient-query", options, async (updatedOptions) => { const response = assertResponse((await this._blobContext.query({ abortSignal: options.abortSignal, queryRequest: { queryType: "SQL", expression: query, inputSerialization: toQuerySerialization(options.inputTextConfiguration), outputSerialization: toQuerySerialization(options.outputTextConfiguration), }, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, cpkInfo: options.customerProvidedKey, tracingOptions: updatedOptions.tracingOptions, }))); return new BlobQueryResponse(response, { abortSignal: options.abortSignal, onProgress: options.onProgress, onError: options.onError, }); }); } /** * Creates a new block blob, or updates the content of an existing block blob. * Updating an existing block blob overwrites any existing metadata on the blob. * Partial updates are not supported; the content of the existing blob is * overwritten with the new content. To perform a partial update of a block blob's, * use {@link stageBlock} and {@link commitBlockList}. * * This is a non-parallel uploading method, please use {@link uploadFile}, * {@link uploadStream} or {@link uploadBrowserData} for better performance * with concurrency uploading. * * @see https://learn.microsoft.com/rest/api/storageservices/put-blob * * @param body - Blob, string, ArrayBuffer, ArrayBufferView or a function * which returns a new Readable stream whose offset is from data source beginning. * @param contentLength - Length of body in bytes. Use Buffer.byteLength() to calculate body length for a * string including non non-Base64/Hex-encoded characters. * @param options - Options to the Block Blob Upload operation. * @returns Response data for the Block Blob Upload operation. * * Example usage: * * ```ts snippet:ClientsUpload * import { BlobServiceClient } from "@azure/storage-blob"; * import { DefaultAzureCredential } from "@azure/identity"; * * const account = ""; * const blobServiceClient = new BlobServiceClient( * `https://${account}.blob.core.windows.net`, * new DefaultAzureCredential(), * ); * * const containerName = ""; * const blobName = ""; * const containerClient = blobServiceClient.getContainerClient(containerName); * const blockBlobClient = containerClient.getBlockBlobClient(blobName); * * const content = "Hello world!"; * const uploadBlobResponse = await blockBlobClient.upload(content, content.length); * ``` */ async upload(body, contentLength, options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlockBlobClient-upload", options, async (updatedOptions) => { const parameters = { abortSignal: options.abortSignal, blobHttpHeaders: options.blobHTTPHeaders, leaseAccessConditions: options.conditions, metadata: options.metadata, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, requestOptions: { onUploadProgress: options.onProgress, }, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, immutabilityPolicyExpiry: options.immutabilityPolicy?.expiriesOn, immutabilityPolicyMode: options.immutabilityPolicy?.policyMode, legalHold: options.legalHold, tier: toAccessTier(options.tier), blobTagsString: toBlobTagsString(options.tags), tracingOptions: updatedOptions.tracingOptions, }; const uploadBodyParameters = await setUploadChecksumParameters(body, contentLength, parameters, options, this.blobClientConfig?.uploadContentChecksumAlgorithm); return assertResponse(await this.blockBlobContext.upload(uploadBodyParameters.contentLength, uploadBodyParameters.body, parameters)); }); } /** * Creates a new Block Blob where the contents of the blob are read from a given URL. * This API is supported beginning with the 2020-04-08 version. Partial updates * are not supported with Put Blob from URL; the content of an existing blob is overwritten with * the content of the new blob. To perform partial updates to a block blob’s contents using a * source URL, use {@link stageBlockFromURL} and {@link commitBlockList}. * * @param sourceURL - Specifies the URL of the blob. The value * may be a URL of up to 2 KB in length that specifies a blob. * The value should be URL-encoded as it would appear * in a request URI. The source blob must either be public * or must be authenticated via a shared access signature. * If the source blob is public, no authentication is required * to perform the operation. Here are some examples of source object URLs: * - https://myaccount.blob.core.windows.net/mycontainer/myblob * - https://myaccount.blob.core.windows.net/mycontainer/myblob?snapshot= * @param options - Optional parameters. */ async syncUploadFromURL(sourceURL, options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlockBlobClient-syncUploadFromURL", options, async (updatedOptions) => { return assertResponse(await this.blockBlobContext.putBlobFromUrl(0, sourceURL, { ...options, blobHttpHeaders: options.blobHTTPHeaders, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, sourceModifiedAccessConditions: { sourceIfMatch: options.sourceConditions?.ifMatch, sourceIfModifiedSince: options.sourceConditions?.ifModifiedSince, sourceIfNoneMatch: options.sourceConditions?.ifNoneMatch, sourceIfUnmodifiedSince: options.sourceConditions?.ifUnmodifiedSince, sourceIfTags: options.sourceConditions?.tagConditions, }, cpkInfo: options.customerProvidedKey, copySourceAuthorization: httpAuthorizationToString(options.sourceAuthorization), tier: toAccessTier(options.tier), blobTagsString: toBlobTagsString(options.tags), copySourceTags: options.copySourceTags, fileRequestIntent: options.sourceShareTokenIntent, tracingOptions: updatedOptions.tracingOptions, sourceCpkInfo: { sourceEncryptionKey: options.sourceCustomerProvidedKey?.encryptionKey, sourceEncryptionAlgorithm: options.sourceCustomerProvidedKey?.encryptionAlgorithm, sourceEncryptionKeySha256: options.sourceCustomerProvidedKey?.encryptionKeySha256, }, })); }); } /** * Uploads the specified block to the block blob's "staging area" to be later * committed by a call to commitBlockList. * @see https://learn.microsoft.com/rest/api/storageservices/put-block * * @param blockId - A 64-byte value that is base64-encoded * @param body - Data to upload to the staging area. * @param contentLength - Number of bytes to upload. * @param options - Options to the Block Blob Stage Block operation. * @returns Response data for the Block Blob Stage Block operation. */ async stageBlock(blockId, body, contentLength, options = {}) { ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlockBlobClient-stageBlock", options, async (updatedOptions) => { const parameters = { abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, requestOptions: { onUploadProgress: options.onProgress, }, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, tracingOptions: updatedOptions.tracingOptions, }; const uploadBodyParameters = await setUploadChecksumParameters(body, contentLength, parameters, options, this.blobClientConfig?.uploadContentChecksumAlgorithm); return assertResponse(await this.blockBlobContext.stageBlock(blockId, uploadBodyParameters.contentLength, uploadBodyParameters.body, parameters)); }); } /** * The Stage Block From URL operation creates a new block to be committed as part * of a blob where the contents are read from a URL. * This API is available starting in version 2018-03-28. * @see https://learn.microsoft.com/rest/api/storageservices/put-block-from-url * * @param blockId - A 64-byte value that is base64-encoded * @param sourceURL - Specifies the URL of the blob. The value * may be a URL of up to 2 KB in length that specifies a blob. * The value should be URL-encoded as it would appear * in a request URI. The source blob must either be public * or must be authenticated via a shared access signature. * If the source blob is public, no authentication is required * to perform the operation. Here are some examples of source object URLs: * - https://myaccount.blob.core.windows.net/mycontainer/myblob * - https://myaccount.blob.core.windows.net/mycontainer/myblob?snapshot= * @param offset - From which position of the blob to download, greater than or equal to 0 * @param count - How much data to be downloaded, greater than 0. Will download to the end when undefined * @param options - Options to the Block Blob Stage Block From URL operation. * @returns Response data for the Block Blob Stage Block From URL operation. */ async stageBlockFromURL(blockId, sourceURL, offset = 0, count, options = {}) { ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlockBlobClient-stageBlockFromURL", options, async (updatedOptions) => { return assertResponse(await this.blockBlobContext.stageBlockFromURL(blockId, 0, sourceURL, { abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, sourceContentMD5: options.sourceContentMD5, sourceContentCrc64: options.sourceContentCrc64, sourceRange: offset === 0 && !count ? undefined : rangeToString({ offset, count }), cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, copySourceAuthorization: httpAuthorizationToString(options.sourceAuthorization), fileRequestIntent: options.sourceShareTokenIntent, tracingOptions: updatedOptions.tracingOptions, sourceCpkInfo: { sourceEncryptionKey: options.sourceCustomerProvidedKey?.encryptionKey, sourceEncryptionAlgorithm: options.sourceCustomerProvidedKey?.encryptionAlgorithm, sourceEncryptionKeySha256: options.sourceCustomerProvidedKey?.encryptionKeySha256, }, })); }); } /** * Writes a blob by specifying the list of block IDs that make up the blob. * In order to be written as part of a blob, a block must have been successfully written * to the server in a prior {@link stageBlock} operation. You can call {@link commitBlockList} to * update a blob by uploading only those blocks that have changed, then committing the new and existing * blocks together. Any blocks not specified in the block list and permanently deleted. * @see https://learn.microsoft.com/rest/api/storageservices/put-block-list * * @param blocks - Array of 64-byte value that is base64-encoded * @param options - Options to the Block Blob Commit Block List operation. * @returns Response data for the Block Blob Commit Block List operation. */ async commitBlockList(blocks, options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlockBlobClient-commitBlockList", options, async (updatedOptions) => { return assertResponse(await this.blockBlobContext.commitBlockList({ latest: blocks }, { abortSignal: options.abortSignal, blobHttpHeaders: options.blobHTTPHeaders, leaseAccessConditions: options.conditions, metadata: options.metadata, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, immutabilityPolicyExpiry: options.immutabilityPolicy?.expiriesOn, immutabilityPolicyMode: options.immutabilityPolicy?.policyMode, legalHold: options.legalHold, tier: toAccessTier(options.tier), blobTagsString: toBlobTagsString(options.tags), tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Returns the list of blocks that have been uploaded as part of a block blob * using the specified block list filter. * @see https://learn.microsoft.com/rest/api/storageservices/get-block-list * * @param listType - Specifies whether to return the list of committed blocks, * the list of uncommitted blocks, or both lists together. * @param options - Options to the Block Blob Get Block List operation. * @returns Response data for the Block Blob Get Block List operation. */ async getBlockList(listType, options = {}) { return tracingClient.withSpan("BlockBlobClient-getBlockList", options, async (updatedOptions) => { const res = assertResponse(await this.blockBlobContext.getBlockList(listType, { abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, tracingOptions: updatedOptions.tracingOptions, })); if (!res.committedBlocks) { res.committedBlocks = []; } if (!res.uncommittedBlocks) { res.uncommittedBlocks = []; } return res; }); } // High level functions /** * Uploads a Buffer(Node.js)/Blob(browsers)/ArrayBuffer/ArrayBufferView object to a BlockBlob. * * When data length is no more than the specifiled {@link BlockBlobParallelUploadOptions.maxSingleShotSize} (default is * {@link BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES}), this method will use 1 {@link upload} call to finish the upload. * Otherwise, this method will call {@link stageBlock} to upload blocks, and finally call {@link commitBlockList} * to commit the block list. * * A common {@link BlockBlobParallelUploadOptions.blobHTTPHeaders} option to set is * `blobContentType`, enabling the browser to provide * functionality based on file type. * * @param data - Buffer(Node.js), Blob, ArrayBuffer or ArrayBufferView * @param options - */ async uploadData(data, options = {}) { return tracingClient.withSpan("BlockBlobClient-uploadData", options, async (updatedOptions) => { { let buffer; if (data instanceof Buffer) { buffer = data; } else if (data instanceof ArrayBuffer) { buffer = Buffer.from(data); } else { data = data; buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength); } return this.uploadSeekableInternal((offset, size) => buffer.slice(offset, offset + size), buffer.byteLength, updatedOptions); } }); } /** * ONLY AVAILABLE IN BROWSERS. * * Uploads a browser Blob/File/ArrayBuffer/ArrayBufferView object to block blob. * * When buffer length lesser than or equal to 256MB, this method will use 1 upload call to finish the upload. * Otherwise, this method will call {@link stageBlock} to upload blocks, and finally call * {@link commitBlockList} to commit the block list. * * A common {@link BlockBlobParallelUploadOptions.blobHTTPHeaders} option to set is * `blobContentType`, enabling the browser to provide * functionality based on file type. * * @deprecated Use {@link uploadData} instead. * * @param browserData - Blob, File, ArrayBuffer or ArrayBufferView * @param options - Options to upload browser data. * @returns Response data for the Blob Upload operation. */ async uploadBrowserData(browserData, options = {}) { return tracingClient.withSpan("BlockBlobClient-uploadBrowserData", options, async (updatedOptions) => { const browserBlob = new Blob([browserData]); return this.uploadSeekableInternal((offset, size) => browserBlob.slice(offset, offset + size), browserBlob.size, updatedOptions); }); } /** * * Uploads data to block blob. Requires a bodyFactory as the data source, * which need to return a {@link HttpRequestBody} object with the offset and size provided. * * When data length is no more than the specified {@link BlockBlobParallelUploadOptions.maxSingleShotSize} (default is * {@link BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES}), this method will use 1 {@link upload} call to finish the upload. * Otherwise, this method will call {@link stageBlock} to upload blocks, and finally call {@link commitBlockList} * to commit the block list. * * @param bodyFactory - * @param size - size of the data to upload. * @param options - Options to Upload to Block Blob operation. * @returns Response data for the Blob Upload operation. */ async uploadSeekableInternal(bodyFactory, size, options = {}) { let blockSize = options.blockSize ?? 0; if (blockSize < 0 || blockSize > BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES) { throw new RangeError(`blockSize option must be >= 0 and <= ${BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES}`); } const maxSingleShotSize = options.maxSingleShotSize ?? BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES; if (maxSingleShotSize < 0 || maxSingleShotSize > BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES) { throw new RangeError(`maxSingleShotSize option must be >= 0 and <= ${BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES}`); } if (blockSize === 0) { if (size > BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES * BLOCK_BLOB_MAX_BLOCKS) { throw new RangeError(`${size} is too larger to upload to a block blob.`); } if (size > maxSingleShotSize) { blockSize = Math.ceil(size / BLOCK_BLOB_MAX_BLOCKS); if (blockSize < DEFAULT_BLOB_DOWNLOAD_BLOCK_BYTES) { blockSize = DEFAULT_BLOB_DOWNLOAD_BLOCK_BYTES; } } } if (!options.blobHTTPHeaders) { options.blobHTTPHeaders = {}; } if (!options.conditions) { options.conditions = {}; } return tracingClient.withSpan("BlockBlobClient-uploadSeekableInternal", options, async (updatedOptions) => { if (size <= maxSingleShotSize) { return assertResponse(await this.upload(bodyFactory(0, size), size, updatedOptions)); } const numBlocks = Math.floor((size - 1) / blockSize) + 1; if (numBlocks > BLOCK_BLOB_MAX_BLOCKS) { throw new RangeError(`The buffer's size is too big or the BlockSize is too small;` + `the number of blocks must be <= ${BLOCK_BLOB_MAX_BLOCKS}`); } const blockList = []; const blockIDPrefix = randomUUID(); let transferProgress = 0; const batch = new Batch(options.concurrency); for (let i = 0; i < numBlocks; i++) { batch.addOperation(async () => { const blockID = generateBlockID(blockIDPrefix, i); const start = blockSize * i; const end = i === numBlocks - 1 ? size : start + blockSize; const contentLength = end - start; blockList.push(blockID); await this.stageBlock(blockID, bodyFactory(start, contentLength), contentLength, { abortSignal: options.abortSignal, conditions: options.conditions, encryptionScope: options.encryptionScope, tracingOptions: updatedOptions.tracingOptions, contentChecksumAlgorithm: options.contentChecksumAlgorithm, }); // Update progress after block is successfully uploaded to server, in case of block trying // TODO: Hook with convenience layer progress event in finer level transferProgress += contentLength; if (options.onProgress) { options.onProgress({ loadedBytes: transferProgress, }); } }); } await batch.do(); return this.commitBlockList(blockList, updatedOptions); }); } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * Uploads a local file in blocks to a block blob. * * When file size lesser than or equal to 256MB, this method will use 1 upload call to finish the upload. * Otherwise, this method will call stageBlock to upload blocks, and finally call commitBlockList * to commit the block list. * * @param filePath - Full path of local file * @param options - Options to Upload to Block Blob operation. * @returns Response data for the Blob Upload operation. */ async uploadFile(filePath, options = {}) { return tracingClient.withSpan("BlockBlobClient-uploadFile", options, async (updatedOptions) => { const size = (await fsStat(filePath)).size; return this.uploadSeekableInternal((offset, count) => { return () => fsCreateReadStream(filePath, { autoClose: true, end: count ? offset + count - 1 : Infinity, start: offset, }); }, size, { ...options, tracingOptions: updatedOptions.tracingOptions, }); }); } /** * ONLY AVAILABLE IN NODE.JS RUNTIME. * * Uploads a Node.js Readable stream into block blob. * * PERFORMANCE IMPROVEMENT TIPS: * * Input stream highWaterMark is better to set a same value with bufferSize * parameter, which will avoid Buffer.concat() operations. * * @param stream - Node.js Readable stream * @param bufferSize - Size of every buffer allocated, also the block size in the uploaded block blob. Default value is 8MB * @param maxConcurrency - Max concurrency indicates the max number of buffers that can be allocated, * positive correlation with max uploading concurrency. Default value is 5 * @param options - Options to Upload Stream to Block Blob operation. * @returns Response data for the Blob Upload operation. */ async uploadStream(stream, bufferSize = DEFAULT_BLOCK_BUFFER_SIZE_BYTES, maxConcurrency = 5, options = {}) { if (!options.blobHTTPHeaders) { options.blobHTTPHeaders = {}; } if (!options.conditions) { options.conditions = {}; } return tracingClient.withSpan("BlockBlobClient-uploadStream", options, async (updatedOptions) => { let blockNum = 0; const blockIDPrefix = randomUUID(); let transferProgress = 0; const blockList = []; const scheduler = new BufferScheduler(stream, bufferSize, maxConcurrency, async (body, length) => { const blockID = generateBlockID(blockIDPrefix, blockNum); blockList.push(blockID); blockNum++; await this.stageBlock(blockID, body, length, { customerProvidedKey: options.customerProvidedKey, conditions: options.conditions, encryptionScope: options.encryptionScope, tracingOptions: updatedOptions.tracingOptions, contentChecksumAlgorithm: options.contentChecksumAlgorithm, }); // Update progress after block is successfully uploaded to server, in case of block trying transferProgress += length; if (options.onProgress) { options.onProgress({ loadedBytes: transferProgress }); } }, // concurrency should set a smaller value than maxConcurrency, which is helpful to // reduce the possibility when a outgoing handler waits for stream data, in // this situation, outgoing handlers are blocked. // Outgoing queue shouldn't be empty. Math.ceil((maxConcurrency / 4) * 3)); await scheduler.do(); return assertResponse(await this.commitBlockList(blockList, { ...options, tracingOptions: updatedOptions.tracingOptions, })); }); } } /** * PageBlobClient defines a set of operations applicable to page blobs. */ class PageBlobClient extends BlobClient { /** * pageBlobsContext provided by protocol layer. */ pageBlobContext; constructor(urlOrConnectionString, credentialOrPipelineOrContainerName, blobNameOrOptions, // Legacy, no fix for eslint error without breaking. Disable it for this interface. /* eslint-disable-next-line @azure/azure-sdk/ts-naming-options*/ options) { // In TypeScript we cannot simply pass all parameters to super() like below so have to duplicate the code instead. // super(s, credentialOrPipelineOrContainerNameOrOptions, blobNameOrOptions, options); let pipeline; let url; options = options || {}; if (isPipelineLike(credentialOrPipelineOrContainerName)) { // (url: string, pipeline: Pipeline) url = urlOrConnectionString; pipeline = credentialOrPipelineOrContainerName; options = blobNameOrOptions; } else if ((credentialOrPipelineOrContainerName instanceof StorageSharedKeyCredential) || credentialOrPipelineOrContainerName instanceof AnonymousCredential || isTokenCredential(credentialOrPipelineOrContainerName)) { // (url: string, credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential, options?: StoragePipelineOptions) url = urlOrConnectionString; options = blobNameOrOptions; pipeline = newPipeline(credentialOrPipelineOrContainerName, options); } else if (!credentialOrPipelineOrContainerName && typeof credentialOrPipelineOrContainerName !== "string") { // (url: string, credential?: StorageSharedKeyCredential | AnonymousCredential | TokenCredential, options?: StoragePipelineOptions) // The second parameter is undefined. Use anonymous credential. url = urlOrConnectionString; options = blobNameOrOptions; pipeline = newPipeline(new AnonymousCredential(), options); } else if (credentialOrPipelineOrContainerName && typeof credentialOrPipelineOrContainerName === "string" && blobNameOrOptions && typeof blobNameOrOptions === "string") { // (connectionString: string, containerName: string, blobName: string, options?: StoragePipelineOptions) const containerName = credentialOrPipelineOrContainerName; const blobName = blobNameOrOptions; const extractedCreds = extractConnectionStringParts(urlOrConnectionString); if (extractedCreds.kind === "AccountConnString") { { const sharedKeyCredential = new StorageSharedKeyCredential(extractedCreds.accountName, extractedCreds.accountKey); url = appendToURLPath(appendToURLPath(extractedCreds.url, encodeURIComponent(containerName)), encodeURIComponent(blobName)); if (!options.proxyOptions) { options.proxyOptions = getDefaultProxySettings(extractedCreds.proxyUri); } pipeline = newPipeline(sharedKeyCredential, options); } } else if (extractedCreds.kind === "SASConnString") { url = appendToURLPath(appendToURLPath(extractedCreds.url, encodeURIComponent(containerName)), encodeURIComponent(blobName)) + "?" + extractedCreds.accountSas; pipeline = newPipeline(new AnonymousCredential(), options); } else { throw new Error("Connection string must be either an Account connection string or a SAS connection string"); } } else { throw new Error("Expecting non-empty strings for containerName and blobName parameters"); } super(url, pipeline); this.pageBlobContext = this.storageClientContext.pageBlob; this.blobClientConfig = options; } /** * Creates a new PageBlobClient object identical to the source but with the * specified snapshot timestamp. * Provide "" will remove the snapshot and return a Client to the base blob. * * @param snapshot - The snapshot timestamp. * @returns A new PageBlobClient object identical to the source but with the specified snapshot timestamp. */ withSnapshot(snapshot) { return new PageBlobClient(setURLParameter(this.url, URLConstants.Parameters.SNAPSHOT, snapshot.length === 0 ? undefined : snapshot), this.pipeline, this.blobClientConfig); } /** * Creates a page blob of the specified length. Call uploadPages to upload data * data to a page blob. * @see https://learn.microsoft.com/rest/api/storageservices/put-blob * * @param size - size of the page blob. * @param options - Options to the Page Blob Create operation. * @returns Response data for the Page Blob Create operation. */ async create(size, options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("PageBlobClient-create", options, async (updatedOptions) => { return assertResponse(await this.pageBlobContext.create(0, size, { abortSignal: options.abortSignal, blobHttpHeaders: options.blobHTTPHeaders, blobSequenceNumber: options.blobSequenceNumber, leaseAccessConditions: options.conditions, metadata: options.metadata, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, immutabilityPolicyExpiry: options.immutabilityPolicy?.expiriesOn, immutabilityPolicyMode: options.immutabilityPolicy?.policyMode, legalHold: options.legalHold, tier: toAccessTier(options.tier), blobTagsString: toBlobTagsString(options.tags), tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Creates a page blob of the specified length. Call uploadPages to upload data * data to a page blob. If the blob with the same name already exists, the content * of the existing blob will remain unchanged. * @see https://learn.microsoft.com/rest/api/storageservices/put-blob * * @param size - size of the page blob. * @param options - */ async createIfNotExists(size, options = {}) { return tracingClient.withSpan("PageBlobClient-createIfNotExists", options, async (updatedOptions) => { try { const conditions = { ifNoneMatch: ETagAny }; const res = assertResponse(await this.create(size, { ...options, conditions, tracingOptions: updatedOptions.tracingOptions, })); return { succeeded: true, ...res, _response: res._response, // _response is made non-enumerable }; } catch (e) { if (e.details?.errorCode === "BlobAlreadyExists") { return { succeeded: false, ...e.response?.parsedHeaders, _response: e.response, }; } throw e; } }); } /** * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. * @see https://learn.microsoft.com/rest/api/storageservices/put-page * * @param body - Data to upload * @param offset - Offset of destination page blob * @param count - Content length of the body, also number of bytes to be uploaded * @param options - Options to the Page Blob Upload Pages operation. * @returns Response data for the Page Blob Upload Pages operation. */ async uploadPages(body, offset, count, options = {}) { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("PageBlobClient-uploadPages", options, async (updatedOptions) => { const parameters = { abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, requestOptions: { onUploadProgress: options.onProgress, }, range: rangeToString({ offset, count }), sequenceNumberAccessConditions: options.conditions, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, tracingOptions: updatedOptions.tracingOptions, }; const uploadBodyParameters = await setUploadChecksumParameters(body, count, parameters, options, this.blobClientConfig?.uploadContentChecksumAlgorithm); return assertResponse(await this.pageBlobContext.uploadPages(uploadBodyParameters.contentLength, uploadBodyParameters.body, parameters)); }); } /** * The Upload Pages operation writes a range of pages to a page blob where the * contents are read from a URL. * @see https://learn.microsoft.com/rest/api/storageservices/put-page-from-url * * @param sourceURL - Specify a URL to the copy source, Shared Access Signature(SAS) maybe needed for authentication * @param sourceOffset - The source offset to copy from. Pass 0 to copy from the beginning of source page blob * @param destOffset - Offset of destination page blob * @param count - Number of bytes to be uploaded from source page blob * @param options - */ async uploadPagesFromURL(sourceURL, sourceOffset, destOffset, count, options = {}) { options.conditions = options.conditions || {}; options.sourceConditions = options.sourceConditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("PageBlobClient-uploadPagesFromURL", options, async (updatedOptions) => { return assertResponse(await this.pageBlobContext.uploadPagesFromURL(sourceURL, rangeToString({ offset: sourceOffset, count }), 0, rangeToString({ offset: destOffset, count }), { abortSignal: options.abortSignal, sourceContentMD5: options.sourceContentMD5, sourceContentCrc64: options.sourceContentCrc64, leaseAccessConditions: options.conditions, sequenceNumberAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, sourceModifiedAccessConditions: { sourceIfMatch: options.sourceConditions?.ifMatch, sourceIfModifiedSince: options.sourceConditions?.ifModifiedSince, sourceIfNoneMatch: options.sourceConditions?.ifNoneMatch, sourceIfUnmodifiedSince: options.sourceConditions?.ifUnmodifiedSince, }, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, copySourceAuthorization: httpAuthorizationToString(options.sourceAuthorization), fileRequestIntent: options.sourceShareTokenIntent, tracingOptions: updatedOptions.tracingOptions, sourceCpkInfo: { sourceEncryptionKey: options.sourceCustomerProvidedKey?.encryptionKey, sourceEncryptionAlgorithm: options.sourceCustomerProvidedKey?.encryptionAlgorithm, sourceEncryptionKeySha256: options.sourceCustomerProvidedKey?.encryptionKeySha256, }, })); }); } /** * Frees the specified pages from the page blob. * @see https://learn.microsoft.com/rest/api/storageservices/put-page * * @param offset - Starting byte position of the pages to clear. * @param count - Number of bytes to clear. * @param options - Options to the Page Blob Clear Pages operation. * @returns Response data for the Page Blob Clear Pages operation. */ async clearPages(offset = 0, count, options = {}) { options.conditions = options.conditions || {}; return tracingClient.withSpan("PageBlobClient-clearPages", options, async (updatedOptions) => { return assertResponse(await this.pageBlobContext.clearPages(0, { abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, range: rangeToString({ offset, count }), sequenceNumberAccessConditions: options.conditions, cpkInfo: options.customerProvidedKey, encryptionScope: options.encryptionScope, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Returns the list of valid page ranges for a page blob or snapshot of a page blob. * @see https://learn.microsoft.com/rest/api/storageservices/get-page-ranges * * @param offset - Starting byte position of the page ranges. * @param count - Number of bytes to get. * @param options - Options to the Page Blob Get Ranges operation. * @returns Response data for the Page Blob Get Ranges operation. */ async getPageRanges(offset = 0, count, options = {}) { options.conditions = options.conditions || {}; return tracingClient.withSpan("PageBlobClient-getPageRanges", options, async (updatedOptions) => { const response = assertResponse(await this.pageBlobContext.getPageRanges({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, range: rangeToString({ offset, count }), tracingOptions: updatedOptions.tracingOptions, })); return rangeResponseFromModel(response); }); } /** * getPageRangesSegment returns a single segment of page ranges starting from the * specified Marker. Use an empty Marker to start enumeration from the beginning. * After getting a segment, process it, and then call getPageRangesSegment again * (passing the the previously-returned Marker) to get the next segment. * @see https://learn.microsoft.com/rest/api/storageservices/get-page-ranges * * @param offset - Starting byte position of the page ranges. * @param count - Number of bytes to get. * @param marker - A string value that identifies the portion of the list to be returned with the next list operation. * @param options - Options to PageBlob Get Page Ranges Segment operation. */ async listPageRangesSegment(offset = 0, count, marker, options = {}) { return tracingClient.withSpan("PageBlobClient-getPageRangesSegment", options, async (updatedOptions) => { return assertResponse(await this.pageBlobContext.getPageRanges({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, range: rangeToString({ offset, count }), marker: marker, maxPageSize: options.maxPageSize, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Returns an AsyncIterableIterator for {@link PageBlobGetPageRangesResponseModel} * * @param offset - Starting byte position of the page ranges. * @param count - Number of bytes to get. * @param marker - A string value that identifies the portion of * the get of page ranges to be returned with the next getting operation. The * operation returns the ContinuationToken value within the response body if the * getting operation did not return all page ranges remaining within the current page. * The ContinuationToken value can be used as the value for * the marker parameter in a subsequent call to request the next page of get * items. The marker value is opaque to the client. * @param options - Options to List Page Ranges operation. */ async *listPageRangeItemSegments(offset = 0, count, marker, options = {}) { let getPageRangeItemSegmentsResponse; if (!!marker || marker === undefined) { do { getPageRangeItemSegmentsResponse = await this.listPageRangesSegment(offset, count, marker, options); marker = getPageRangeItemSegmentsResponse.continuationToken; yield await getPageRangeItemSegmentsResponse; } while (marker); } } /** * Returns an AsyncIterableIterator of {@link PageRangeInfo} objects * * @param offset - Starting byte position of the page ranges. * @param count - Number of bytes to get. * @param options - Options to List Page Ranges operation. */ async *listPageRangeItems(offset = 0, count, options = {}) { let marker; for await (const getPageRangesSegment of this.listPageRangeItemSegments(offset, count, marker, options)) { yield* ExtractPageRangeInfoItems(getPageRangesSegment); } } /** * Returns an async iterable iterator to list of page ranges for a page blob. * @see https://learn.microsoft.com/rest/api/storageservices/get-page-ranges * * .byPage() returns an async iterable iterator to list of page ranges for a page blob. * * ```ts snippet:ClientsListPageBlobs * import { BlobServiceClient } from "@azure/storage-blob"; * import { DefaultAzureCredential } from "@azure/identity"; * * const account = ""; * const blobServiceClient = new BlobServiceClient( * `https://${account}.blob.core.windows.net`, * new DefaultAzureCredential(), * ); * * const containerName = ""; * const blobName = ""; * const containerClient = blobServiceClient.getContainerClient(containerName); * const pageBlobClient = containerClient.getPageBlobClient(blobName); * * // Example using `for await` syntax * let i = 1; * for await (const pageRange of pageBlobClient.listPageRanges()) { * console.log(`Page range ${i++}: ${pageRange.start} - ${pageRange.end}`); * } * * // Example using `iter.next()` syntax * i = 1; * const iter = pageBlobClient.listPageRanges(); * let { value, done } = await iter.next(); * while (!done) { * console.log(`Page range ${i++}: ${value.start} - ${value.end}`); * ({ value, done } = await iter.next()); * } * * // Example using `byPage()` syntax * i = 1; * for await (const page of pageBlobClient.listPageRanges().byPage({ maxPageSize: 20 })) { * for (const pageRange of page.pageRange || []) { * console.log(`Page range ${i++}: ${pageRange.start} - ${pageRange.end}`); * } * } * * // Example using paging with a marker * i = 1; * let iterator = pageBlobClient.listPageRanges().byPage({ maxPageSize: 2 }); * let response = (await iterator.next()).value; * // Prints 2 page ranges * if (response.pageRange) { * for (const pageRange of response.pageRange) { * console.log(`Page range ${i++}: ${pageRange.start} - ${pageRange.end}`); * } * } * // Gets next marker * let marker = response.continuationToken; * // Passing next marker as continuationToken * iterator = pageBlobClient.listPageRanges().byPage({ continuationToken: marker, maxPageSize: 10 }); * response = (await iterator.next()).value; * // Prints 10 page ranges * if (response.pageRange) { * for (const pageRange of response.pageRange) { * console.log(`Page range ${i++}: ${pageRange.start} - ${pageRange.end}`); * } * } * ``` * * @param offset - Starting byte position of the page ranges. * @param count - Number of bytes to get. * @param options - Options to the Page Blob Get Ranges operation. * @returns An asyncIterableIterator that supports paging. */ listPageRanges(offset = 0, count, options = {}) { options.conditions = options.conditions || {}; // AsyncIterableIterator to iterate over blobs const iter = this.listPageRangeItems(offset, count, options); return { /** * The next method, part of the iteration protocol */ next() { return iter.next(); }, /** * The connection to the async iterator, part of the iteration protocol */ [Symbol.asyncIterator]() { return this; }, /** * Return an AsyncIterableIterator that works a page at a time */ byPage: (settings = {}) => { return this.listPageRangeItemSegments(offset, count, settings.continuationToken, { maxPageSize: settings.maxPageSize, ...options, }); }, }; } /** * Gets the collection of page ranges that differ between a specified snapshot and this page blob. * @see https://learn.microsoft.com/rest/api/storageservices/get-page-ranges * * @param offset - Starting byte position of the page blob * @param count - Number of bytes to get ranges diff. * @param prevSnapshot - Timestamp of snapshot to retrieve the difference. * @param options - Options to the Page Blob Get Page Ranges Diff operation. * @returns Response data for the Page Blob Get Page Range Diff operation. */ async getPageRangesDiff(offset, count, prevSnapshot, options = {}) { options.conditions = options.conditions || {}; return tracingClient.withSpan("PageBlobClient-getPageRangesDiff", options, async (updatedOptions) => { const result = assertResponse(await this.pageBlobContext.getPageRangesDiff({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, prevsnapshot: prevSnapshot, range: rangeToString({ offset, count }), tracingOptions: updatedOptions.tracingOptions, })); return rangeResponseFromModel(result); }); } /** * getPageRangesDiffSegment returns a single segment of page ranges starting from the * specified Marker for difference between previous snapshot and the target page blob. * Use an empty Marker to start enumeration from the beginning. * After getting a segment, process it, and then call getPageRangesDiffSegment again * (passing the the previously-returned Marker) to get the next segment. * @see https://learn.microsoft.com/rest/api/storageservices/get-page-ranges * * @param offset - Starting byte position of the page ranges. * @param count - Number of bytes to get. * @param prevSnapshotOrUrl - Timestamp of snapshot to retrieve the difference or URL of snapshot to retrieve the difference. * @param marker - A string value that identifies the portion of the get to be returned with the next get operation. * @param options - Options to the Page Blob Get Page Ranges Diff operation. */ async listPageRangesDiffSegment(offset, count, prevSnapshotOrUrl, marker, options = {}) { return tracingClient.withSpan("PageBlobClient-getPageRangesDiffSegment", options, async (updatedOptions) => { return assertResponse(await this.pageBlobContext.getPageRangesDiff({ abortSignal: options?.abortSignal, leaseAccessConditions: options?.conditions, modifiedAccessConditions: { ...options?.conditions, ifTags: options?.conditions?.tagConditions, }, prevsnapshot: prevSnapshotOrUrl, range: rangeToString({ offset: offset, count: count, }), marker: marker, maxPageSize: options?.maxPageSize, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Returns an AsyncIterableIterator for {@link PageBlobGetPageRangesDiffResponseModel} * * * @param offset - Starting byte position of the page ranges. * @param count - Number of bytes to get. * @param prevSnapshotOrUrl - Timestamp of snapshot to retrieve the difference or URL of snapshot to retrieve the difference. * @param marker - A string value that identifies the portion of * the get of page ranges to be returned with the next getting operation. The * operation returns the ContinuationToken value within the response body if the * getting operation did not return all page ranges remaining within the current page. * The ContinuationToken value can be used as the value for * the marker parameter in a subsequent call to request the next page of get * items. The marker value is opaque to the client. * @param options - Options to the Page Blob Get Page Ranges Diff operation. */ async *listPageRangeDiffItemSegments(offset, count, prevSnapshotOrUrl, marker, options) { let getPageRangeItemSegmentsResponse; if (!!marker || marker === undefined) { do { getPageRangeItemSegmentsResponse = await this.listPageRangesDiffSegment(offset, count, prevSnapshotOrUrl, marker, options); marker = getPageRangeItemSegmentsResponse.continuationToken; yield await getPageRangeItemSegmentsResponse; } while (marker); } } /** * Returns an AsyncIterableIterator of {@link PageRangeInfo} objects * * @param offset - Starting byte position of the page ranges. * @param count - Number of bytes to get. * @param prevSnapshotOrUrl - Timestamp of snapshot to retrieve the difference or URL of snapshot to retrieve the difference. * @param options - Options to the Page Blob Get Page Ranges Diff operation. */ async *listPageRangeDiffItems(offset, count, prevSnapshotOrUrl, options) { let marker; for await (const getPageRangesSegment of this.listPageRangeDiffItemSegments(offset, count, prevSnapshotOrUrl, marker, options)) { yield* ExtractPageRangeInfoItems(getPageRangesSegment); } } /** * Returns an async iterable iterator to list of page ranges that differ between a specified snapshot and this page blob. * @see https://learn.microsoft.com/rest/api/storageservices/get-page-ranges * * .byPage() returns an async iterable iterator to list of page ranges that differ between a specified snapshot and this page blob. * * ```ts snippet:ClientsListPageBlobsDiff * import { BlobServiceClient } from "@azure/storage-blob"; * import { DefaultAzureCredential } from "@azure/identity"; * * const account = ""; * const blobServiceClient = new BlobServiceClient( * `https://${account}.blob.core.windows.net`, * new DefaultAzureCredential(), * ); * * const containerName = ""; * const blobName = ""; * const containerClient = blobServiceClient.getContainerClient(containerName); * const pageBlobClient = containerClient.getPageBlobClient(blobName); * * const offset = 0; * const count = 1024; * const previousSnapshot = ""; * // Example using `for await` syntax * let i = 1; * for await (const pageRange of pageBlobClient.listPageRangesDiff(offset, count, previousSnapshot)) { * console.log(`Page range ${i++}: ${pageRange.start} - ${pageRange.end}`); * } * * // Example using `iter.next()` syntax * i = 1; * const iter = pageBlobClient.listPageRangesDiff(offset, count, previousSnapshot); * let { value, done } = await iter.next(); * while (!done) { * console.log(`Page range ${i++}: ${value.start} - ${value.end}`); * ({ value, done } = await iter.next()); * } * * // Example using `byPage()` syntax * i = 1; * for await (const page of pageBlobClient * .listPageRangesDiff(offset, count, previousSnapshot) * .byPage({ maxPageSize: 20 })) { * for (const pageRange of page.pageRange || []) { * console.log(`Page range ${i++}: ${pageRange.start} - ${pageRange.end}`); * } * } * * // Example using paging with a marker * i = 1; * let iterator = pageBlobClient * .listPageRangesDiff(offset, count, previousSnapshot) * .byPage({ maxPageSize: 2 }); * let response = (await iterator.next()).value; * // Prints 2 page ranges * if (response.pageRange) { * for (const pageRange of response.pageRange) { * console.log(`Page range ${i++}: ${pageRange.start} - ${pageRange.end}`); * } * } * // Gets next marker * let marker = response.continuationToken; * // Passing next marker as continuationToken * iterator = pageBlobClient * .listPageRangesDiff(offset, count, previousSnapshot) * .byPage({ continuationToken: marker, maxPageSize: 10 }); * response = (await iterator.next()).value; * // Prints 10 page ranges * if (response.pageRange) { * for (const pageRange of response.pageRange) { * console.log(`Page range ${i++}: ${pageRange.start} - ${pageRange.end}`); * } * } * ``` * * @param offset - Starting byte position of the page ranges. * @param count - Number of bytes to get. * @param prevSnapshot - Timestamp of snapshot to retrieve the difference. * @param options - Options to the Page Blob Get Ranges operation. * @returns An asyncIterableIterator that supports paging. */ listPageRangesDiff(offset, count, prevSnapshot, options = {}) { options.conditions = options.conditions || {}; // AsyncIterableIterator to iterate over blobs const iter = this.listPageRangeDiffItems(offset, count, prevSnapshot, { ...options, }); return { /** * The next method, part of the iteration protocol */ next() { return iter.next(); }, /** * The connection to the async iterator, part of the iteration protocol */ [Symbol.asyncIterator]() { return this; }, /** * Return an AsyncIterableIterator that works a page at a time */ byPage: (settings = {}) => { return this.listPageRangeDiffItemSegments(offset, count, prevSnapshot, settings.continuationToken, { maxPageSize: settings.maxPageSize, ...options, }); }, }; } /** * Gets the collection of page ranges that differ between a specified snapshot and this page blob for managed disks. * @see https://learn.microsoft.com/rest/api/storageservices/get-page-ranges * * @param offset - Starting byte position of the page blob * @param count - Number of bytes to get ranges diff. * @param prevSnapshotUrl - URL of snapshot to retrieve the difference. * @param options - Options to the Page Blob Get Page Ranges Diff operation. * @returns Response data for the Page Blob Get Page Range Diff operation. */ async getPageRangesDiffForManagedDisks(offset, count, prevSnapshotUrl, options = {}) { options.conditions = options.conditions || {}; return tracingClient.withSpan("PageBlobClient-GetPageRangesDiffForManagedDisks", options, async (updatedOptions) => { const response = assertResponse(await this.pageBlobContext.getPageRangesDiff({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, prevSnapshotUrl, range: rangeToString({ offset, count }), tracingOptions: updatedOptions.tracingOptions, })); return rangeResponseFromModel(response); }); } /** * Resizes the page blob to the specified size (which must be a multiple of 512). * @see https://learn.microsoft.com/rest/api/storageservices/set-blob-properties * * @param size - Target size * @param options - Options to the Page Blob Resize operation. * @returns Response data for the Page Blob Resize operation. */ async resize(size, options = {}) { options.conditions = options.conditions || {}; return tracingClient.withSpan("PageBlobClient-resize", options, async (updatedOptions) => { return assertResponse(await this.pageBlobContext.resize(size, { abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, encryptionScope: options.encryptionScope, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Sets a page blob's sequence number. * @see https://learn.microsoft.com/rest/api/storageservices/set-blob-properties * * @param sequenceNumberAction - Indicates how the service should modify the blob's sequence number. * @param sequenceNumber - Required if sequenceNumberAction is max or update * @param options - Options to the Page Blob Update Sequence Number operation. * @returns Response data for the Page Blob Update Sequence Number operation. */ async updateSequenceNumber(sequenceNumberAction, sequenceNumber, options = {}) { options.conditions = options.conditions || {}; return tracingClient.withSpan("PageBlobClient-updateSequenceNumber", options, async (updatedOptions) => { return assertResponse(await this.pageBlobContext.updateSequenceNumber(sequenceNumberAction, { abortSignal: options.abortSignal, blobSequenceNumber: sequenceNumber, leaseAccessConditions: options.conditions, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, tracingOptions: updatedOptions.tracingOptions, })); }); } /** * Begins an operation to start an incremental copy from one page blob's snapshot to this page blob. * The snapshot is copied such that only the differential changes between the previously * copied snapshot are transferred to the destination. * The copied snapshots are complete copies of the original snapshot and can be read or copied from as usual. * @see https://learn.microsoft.com/rest/api/storageservices/incremental-copy-blob * @see https://learn.microsoft.com/azure/virtual-machines/windows/incremental-snapshots * * @param copySource - Specifies the name of the source page blob snapshot. For example, * https://myaccount.blob.core.windows.net/mycontainer/myblob?snapshot= * @param options - Options to the Page Blob Copy Incremental operation. * @returns Response data for the Page Blob Copy Incremental operation. */ async startCopyIncremental(copySource, options = {}) { return tracingClient.withSpan("PageBlobClient-startCopyIncremental", options, async (updatedOptions) => { return assertResponse(await this.pageBlobContext.copyIncremental(copySource, { abortSignal: options.abortSignal, modifiedAccessConditions: { ...options.conditions, ifTags: options.conditions?.tagConditions, }, tracingOptions: updatedOptions.tracingOptions, })); }); } } class InvalidResponseError extends Error { constructor(message) { super(message); this.name = 'InvalidResponseError'; } } class NetworkError extends Error { constructor(code) { const message = `Unable to make request: ${code}\nIf you are using self-hosted runners, please make sure your runner has access to all GitHub endpoints: https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#communication-between-self-hosted-runners-and-github`; super(message); this.code = code; this.name = 'NetworkError'; } } NetworkError.isNetworkErrorCode = (code) => { if (!code) return false; return [ 'ECONNRESET', 'ENOTFOUND', 'ETIMEDOUT', 'ECONNREFUSED', 'EHOSTUNREACH' ].includes(code); }; class UsageError extends Error { constructor() { const message = `Cache storage quota has been hit. Unable to upload any new cache entries.\nMore info on storage limits: https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#calculating-minute-and-storage-spending`; super(message); this.name = 'UsageError'; } } UsageError.isUsageErrorMessage = (msg) => { if (!msg) return false; return msg.includes('insufficient usage'); }; class RateLimitError extends Error { constructor(message) { super(message); this.name = 'RateLimitError'; } } var __awaiter$6 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * Class for tracking the upload state and displaying stats. */ class UploadProgress { constructor(contentLength) { this.contentLength = contentLength; this.sentBytes = 0; this.displayedComplete = false; this.startTime = Date.now(); } /** * Sets the number of bytes sent * * @param sentBytes the number of bytes sent */ setSentBytes(sentBytes) { this.sentBytes = sentBytes; } /** * Returns the total number of bytes transferred. */ getTransferredBytes() { return this.sentBytes; } /** * Returns true if the upload is complete. */ isDone() { return this.getTransferredBytes() === this.contentLength; } /** * Prints the current upload stats. Once the upload completes, this will print one * last line and then stop. */ display() { if (this.displayedComplete) { return; } const transferredBytes = this.sentBytes; const percentage = (100 * (transferredBytes / this.contentLength)).toFixed(1); const elapsedTime = Date.now() - this.startTime; const uploadSpeed = (transferredBytes / (1024 * 1024) / (elapsedTime / 1000)).toFixed(1); info(`Sent ${transferredBytes} of ${this.contentLength} (${percentage}%), ${uploadSpeed} MBs/sec`); if (this.isDone()) { this.displayedComplete = true; } } /** * Returns a function used to handle TransferProgressEvents. */ onProgress() { return (progress) => { this.setSentBytes(progress.loadedBytes); }; } /** * Starts the timer that displays the stats. * * @param delayInMs the delay between each write */ startDisplayTimer(delayInMs = 1000) { const displayCallback = () => { this.display(); if (!this.isDone()) { this.timeoutHandle = setTimeout(displayCallback, delayInMs); } }; this.timeoutHandle = setTimeout(displayCallback, delayInMs); } /** * Stops the timer that displays the stats. As this typically indicates the upload * is complete, this will display one last line, unless the last line has already * been written. */ stopDisplayTimer() { if (this.timeoutHandle) { clearTimeout(this.timeoutHandle); this.timeoutHandle = undefined; } this.display(); } } /** * Uploads a cache archive directly to Azure Blob Storage using the Azure SDK. * This function will display progress information to the console. Concurrency of the * upload is determined by the calling functions. * * @param signedUploadURL * @param archivePath * @param options * @returns */ function uploadCacheArchiveSDK(signedUploadURL, archivePath, options) { return __awaiter$6(this, void 0, void 0, function* () { var _a; const blobClient = new BlobClient(signedUploadURL); const blockBlobClient = blobClient.getBlockBlobClient(); const uploadProgress = new UploadProgress((_a = options === null || options === void 0 ? void 0 : options.archiveSizeBytes) !== null && _a !== void 0 ? _a : 0); // Specify data transfer options const uploadOptions = { blockSize: options === null || options === void 0 ? void 0 : options.uploadChunkSize, concurrency: options === null || options === void 0 ? void 0 : options.uploadConcurrency, // maximum number of parallel transfer workers maxSingleShotSize: 128 * 1024 * 1024, // 128 MiB initial transfer size onProgress: uploadProgress.onProgress() }; try { uploadProgress.startDisplayTimer(); debug(`BlobClient: ${blobClient.name}:${blobClient.accountName}:${blobClient.containerName}`); const response = yield blockBlobClient.uploadFile(archivePath, uploadOptions); // TODO: better management of non-retryable errors if (response._response.status >= 400) { throw new InvalidResponseError(`uploadCacheArchiveSDK: upload failed with status code ${response._response.status}`); } return response; } catch (error) { warning(`uploadCacheArchiveSDK: internal error uploading cache archive: ${error.message}`); throw error; } finally { uploadProgress.stopDisplayTimer(); } }); } var __awaiter$5 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; function isSuccessStatusCode(statusCode) { if (!statusCode) { return false; } return statusCode >= 200 && statusCode < 300; } function isServerErrorStatusCode(statusCode) { if (!statusCode) { return true; } return statusCode >= 500; } function isRetryableStatusCode(statusCode) { if (!statusCode) { return false; } const retryableStatusCodes = [ HttpCodes.BadGateway, HttpCodes.ServiceUnavailable, HttpCodes.GatewayTimeout ]; return retryableStatusCodes.includes(statusCode); } function sleep(milliseconds) { return __awaiter$5(this, void 0, void 0, function* () { return new Promise(resolve => setTimeout(resolve, milliseconds)); }); } function retry(name_1, method_1, getStatusCode_1) { return __awaiter$5(this, arguments, void 0, function* (name, method, getStatusCode, maxAttempts = DefaultRetryAttempts, delay = DefaultRetryDelay, onError = undefined) { let errorMessage = ''; let attempt = 1; while (attempt <= maxAttempts) { let response = undefined; let statusCode = undefined; let isRetryable = false; try { response = yield method(); } catch (error) { if (onError) { response = onError(error); } isRetryable = true; errorMessage = error.message; } if (response) { statusCode = getStatusCode(response); if (!isServerErrorStatusCode(statusCode)) { return response; } } if (statusCode) { isRetryable = isRetryableStatusCode(statusCode); errorMessage = `Cache service responded with ${statusCode}`; } debug(`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`); if (!isRetryable) { debug(`${name} - Error is not retryable`); break; } yield sleep(delay); attempt++; } throw Error(`${name} failed: ${errorMessage}`); }); } function retryTypedResponse(name_1, method_1) { return __awaiter$5(this, arguments, void 0, function* (name, method, maxAttempts = DefaultRetryAttempts, delay = DefaultRetryDelay) { return yield retry(name, method, (response) => response.statusCode, maxAttempts, delay, // If the error object contains the statusCode property, extract it and return // an TypedResponse so it can be processed by the retry logic. (error) => { if (error instanceof HttpClientError) { return { statusCode: error.statusCode, result: null, headers: {}, error }; } else { return undefined; } }); }); } function retryHttpClientResponse(name_1, method_1) { return __awaiter$5(this, arguments, void 0, function* (name, method, maxAttempts = DefaultRetryAttempts, delay = DefaultRetryDelay) { return yield retry(name, method, (response) => response.message.statusCode, maxAttempts, delay); }); } var __awaiter$4 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * Pipes the body of a HTTP response to a stream * * @param response the HTTP response * @param output the writable stream */ function pipeResponseToStream(response, output) { return __awaiter$4(this, void 0, void 0, function* () { const pipeline = require$$0$1.promisify(require$$0$2.pipeline); yield pipeline(response.message, output); }); } /** * Class for tracking the download state and displaying stats. */ class DownloadProgress { constructor(contentLength) { this.contentLength = contentLength; this.segmentIndex = 0; this.segmentSize = 0; this.segmentOffset = 0; this.receivedBytes = 0; this.displayedComplete = false; this.startTime = Date.now(); } /** * Progress to the next segment. Only call this method when the previous segment * is complete. * * @param segmentSize the length of the next segment */ nextSegment(segmentSize) { this.segmentOffset = this.segmentOffset + this.segmentSize; this.segmentIndex = this.segmentIndex + 1; this.segmentSize = segmentSize; this.receivedBytes = 0; debug(`Downloading segment at offset ${this.segmentOffset} with length ${this.segmentSize}...`); } /** * Sets the number of bytes received for the current segment. * * @param receivedBytes the number of bytes received */ setReceivedBytes(receivedBytes) { this.receivedBytes = receivedBytes; } /** * Returns the total number of bytes transferred. */ getTransferredBytes() { return this.segmentOffset + this.receivedBytes; } /** * Returns true if the download is complete. */ isDone() { return this.getTransferredBytes() === this.contentLength; } /** * Prints the current download stats. Once the download completes, this will print one * last line and then stop. */ display() { if (this.displayedComplete) { return; } const transferredBytes = this.segmentOffset + this.receivedBytes; const percentage = (100 * (transferredBytes / this.contentLength)).toFixed(1); const elapsedTime = Date.now() - this.startTime; const downloadSpeed = (transferredBytes / (1024 * 1024) / (elapsedTime / 1000)).toFixed(1); info(`Received ${transferredBytes} of ${this.contentLength} (${percentage}%), ${downloadSpeed} MBs/sec`); if (this.isDone()) { this.displayedComplete = true; } } /** * Returns a function used to handle TransferProgressEvents. */ onProgress() { return (progress) => { this.setReceivedBytes(progress.loadedBytes); }; } /** * Starts the timer that displays the stats. * * @param delayInMs the delay between each write */ startDisplayTimer(delayInMs = 1000) { const displayCallback = () => { this.display(); if (!this.isDone()) { this.timeoutHandle = setTimeout(displayCallback, delayInMs); } }; this.timeoutHandle = setTimeout(displayCallback, delayInMs); } /** * Stops the timer that displays the stats. As this typically indicates the download * is complete, this will display one last line, unless the last line has already * been written. */ stopDisplayTimer() { if (this.timeoutHandle) { clearTimeout(this.timeoutHandle); this.timeoutHandle = undefined; } this.display(); } } /** * Download the cache using the Actions toolkit http-client * * @param archiveLocation the URL for the cache * @param archivePath the local path where the cache is saved */ function downloadCacheHttpClient(archiveLocation, archivePath) { return __awaiter$4(this, void 0, void 0, function* () { const writeStream = fs.createWriteStream(archivePath); const httpClient = new HttpClient('actions/cache'); const downloadResponse = yield retryHttpClientResponse('downloadCache', () => __awaiter$4(this, void 0, void 0, function* () { return httpClient.get(archiveLocation); })); // Abort download if no traffic received over the socket. downloadResponse.message.socket.setTimeout(SocketTimeout, () => { downloadResponse.message.destroy(); debug(`Aborting download, socket timed out after ${SocketTimeout} ms`); }); yield pipeResponseToStream(downloadResponse, writeStream); // Validate download size. const contentLengthHeader = downloadResponse.message.headers['content-length']; if (contentLengthHeader) { const expectedLength = parseInt(contentLengthHeader); const actualLength = getArchiveFileSizeInBytes(archivePath); if (actualLength !== expectedLength) { throw new Error(`Incomplete download. Expected file size: ${expectedLength}, actual file size: ${actualLength}`); } } else { debug('Unable to validate download, no Content-Length header'); } }); } /** * Download the cache using the Actions toolkit http-client concurrently * * @param archiveLocation the URL for the cache * @param archivePath the local path where the cache is saved */ function downloadCacheHttpClientConcurrent(archiveLocation, archivePath, options) { return __awaiter$4(this, void 0, void 0, function* () { var _a; const archiveDescriptor = yield fs.promises.open(archivePath, 'w'); const httpClient = new HttpClient('actions/cache', undefined, { socketTimeout: options.timeoutInMs, keepAlive: true }); try { const res = yield retryHttpClientResponse('downloadCacheMetadata', () => __awaiter$4(this, void 0, void 0, function* () { return yield httpClient.request('HEAD', archiveLocation, null, {}); })); const lengthHeader = res.message.headers['content-length']; if (lengthHeader === undefined || lengthHeader === null) { throw new Error('Content-Length not found on blob response'); } const length = parseInt(lengthHeader); if (Number.isNaN(length)) { throw new Error(`Could not interpret Content-Length: ${length}`); } const downloads = []; const blockSize = 4 * 1024 * 1024; for (let offset = 0; offset < length; offset += blockSize) { const count = Math.min(blockSize, length - offset); downloads.push({ offset, promiseGetter: () => __awaiter$4(this, void 0, void 0, function* () { return yield downloadSegmentRetry(httpClient, archiveLocation, offset, count); }) }); } // reverse to use .pop instead of .shift downloads.reverse(); let actives = 0; let bytesDownloaded = 0; const progress = new DownloadProgress(length); progress.startDisplayTimer(); const progressFn = progress.onProgress(); const activeDownloads = []; let nextDownload; const waitAndWrite = () => __awaiter$4(this, void 0, void 0, function* () { const segment = yield Promise.race(Object.values(activeDownloads)); yield archiveDescriptor.write(segment.buffer, 0, segment.count, segment.offset); actives--; delete activeDownloads[segment.offset]; bytesDownloaded += segment.count; progressFn({ loadedBytes: bytesDownloaded }); }); while ((nextDownload = downloads.pop())) { activeDownloads[nextDownload.offset] = nextDownload.promiseGetter(); actives++; if (actives >= ((_a = options.downloadConcurrency) !== null && _a !== void 0 ? _a : 10)) { yield waitAndWrite(); } } while (actives > 0) { yield waitAndWrite(); } } finally { httpClient.dispose(); yield archiveDescriptor.close(); } }); } function downloadSegmentRetry(httpClient, archiveLocation, offset, count) { return __awaiter$4(this, void 0, void 0, function* () { const retries = 5; let failures = 0; while (true) { try { const timeout = 30000; const result = yield promiseWithTimeout(timeout, downloadSegment(httpClient, archiveLocation, offset, count)); if (typeof result === 'string') { throw new Error('downloadSegmentRetry failed due to timeout'); } return result; } catch (err) { if (failures >= retries) { throw err; } failures++; } } }); } function downloadSegment(httpClient, archiveLocation, offset, count) { return __awaiter$4(this, void 0, void 0, function* () { const partRes = yield retryHttpClientResponse('downloadCachePart', () => __awaiter$4(this, void 0, void 0, function* () { return yield httpClient.get(archiveLocation, { Range: `bytes=${offset}-${offset + count - 1}` }); })); if (!partRes.readBodyBuffer) { throw new Error('Expected HttpClientResponse to implement readBodyBuffer'); } return { offset, count, buffer: yield partRes.readBodyBuffer() }; }); } /** * Download the cache using the Azure Storage SDK. Only call this method if the * URL points to an Azure Storage endpoint. * * @param archiveLocation the URL for the cache * @param archivePath the local path where the cache is saved * @param options the download options with the defaults set */ function downloadCacheStorageSDK(archiveLocation, archivePath, options) { return __awaiter$4(this, void 0, void 0, function* () { var _a; const client = new BlockBlobClient(archiveLocation, undefined, { retryOptions: { // Override the timeout used when downloading each 4 MB chunk // The default is 2 min / MB, which is way too slow tryTimeoutInMs: options.timeoutInMs } }); const properties = yield client.getProperties(); const contentLength = (_a = properties.contentLength) !== null && _a !== void 0 ? _a : -1; if (contentLength < 0) { // We should never hit this condition, but just in case fall back to downloading the // file as one large stream debug('Unable to determine content length, downloading file with http-client...'); yield downloadCacheHttpClient(archiveLocation, archivePath); } else { // Use downloadToBuffer for faster downloads, since internally it splits the // file into 4 MB chunks which can then be parallelized and retried independently // // If the file exceeds the buffer maximum length (~1 GB on 32-bit systems and ~2 GB // on 64-bit systems), split the download into multiple segments // ~2 GB = 2147483647, beyond this, we start getting out of range error. So, capping it accordingly. // Updated segment size to 128MB = 134217728 bytes, to complete a segment faster and fail fast const maxSegmentSize = Math.min(134217728, require$$0$3.constants.MAX_LENGTH); const downloadProgress = new DownloadProgress(contentLength); const fd = fs.openSync(archivePath, 'w'); try { downloadProgress.startDisplayTimer(); const controller = new AbortController(); const abortSignal = controller.signal; while (!downloadProgress.isDone()) { const segmentStart = downloadProgress.segmentOffset + downloadProgress.segmentSize; const segmentSize = Math.min(maxSegmentSize, contentLength - segmentStart); downloadProgress.nextSegment(segmentSize); const result = yield promiseWithTimeout(options.segmentTimeoutInMs || 3600000, client.downloadToBuffer(segmentStart, segmentSize, { abortSignal, concurrency: options.downloadConcurrency, onProgress: downloadProgress.onProgress() })); if (result === 'timeout') { controller.abort(); throw new Error('Aborting cache download as the download time exceeded the timeout.'); } else if (Buffer.isBuffer(result)) { fs.writeFileSync(fd, result); } } } finally { downloadProgress.stopDisplayTimer(); fs.closeSync(fd); } } }); } const promiseWithTimeout = (timeoutMs, promise) => __awaiter$4(void 0, void 0, void 0, function* () { let timeoutHandle; const timeoutPromise = new Promise(resolve => { timeoutHandle = setTimeout(() => resolve('timeout'), timeoutMs); }); return Promise.race([promise, timeoutPromise]).then(result => { clearTimeout(timeoutHandle); return result; }); }); /** * Returns a copy of the upload options with defaults filled in. * * @param copy the original upload options */ function getUploadOptions(copy) { // Defaults if not overriden const result = { useAzureSdk: false, uploadConcurrency: 4, uploadChunkSize: 32 * 1024 * 1024 }; if (copy) { if (typeof copy.useAzureSdk === 'boolean') { result.useAzureSdk = copy.useAzureSdk; } if (typeof copy.uploadConcurrency === 'number') { result.uploadConcurrency = copy.uploadConcurrency; } if (typeof copy.uploadChunkSize === 'number') { result.uploadChunkSize = copy.uploadChunkSize; } } /** * Add env var overrides */ // Cap the uploadConcurrency at 32 result.uploadConcurrency = !isNaN(Number(process.env['CACHE_UPLOAD_CONCURRENCY'])) ? Math.min(32, Number(process.env['CACHE_UPLOAD_CONCURRENCY'])) : result.uploadConcurrency; // Cap the uploadChunkSize at 128MiB result.uploadChunkSize = !isNaN(Number(process.env['CACHE_UPLOAD_CHUNK_SIZE'])) ? Math.min(128 * 1024 * 1024, Number(process.env['CACHE_UPLOAD_CHUNK_SIZE']) * 1024 * 1024) : result.uploadChunkSize; debug(`Use Azure SDK: ${result.useAzureSdk}`); debug(`Upload concurrency: ${result.uploadConcurrency}`); debug(`Upload chunk size: ${result.uploadChunkSize}`); return result; } /** * Returns a copy of the download options with defaults filled in. * * @param copy the original download options */ function getDownloadOptions(copy) { const result = { useAzureSdk: false, concurrentBlobDownloads: true, downloadConcurrency: 8, timeoutInMs: 30000, segmentTimeoutInMs: 600000, lookupOnly: false }; if (copy) { if (typeof copy.useAzureSdk === 'boolean') { result.useAzureSdk = copy.useAzureSdk; } if (typeof copy.concurrentBlobDownloads === 'boolean') { result.concurrentBlobDownloads = copy.concurrentBlobDownloads; } if (typeof copy.downloadConcurrency === 'number') { result.downloadConcurrency = copy.downloadConcurrency; } if (typeof copy.timeoutInMs === 'number') { result.timeoutInMs = copy.timeoutInMs; } if (typeof copy.segmentTimeoutInMs === 'number') { result.segmentTimeoutInMs = copy.segmentTimeoutInMs; } if (typeof copy.lookupOnly === 'boolean') { result.lookupOnly = copy.lookupOnly; } } const segmentDownloadTimeoutMins = process.env['SEGMENT_DOWNLOAD_TIMEOUT_MINS']; if (segmentDownloadTimeoutMins && !isNaN(Number(segmentDownloadTimeoutMins)) && isFinite(Number(segmentDownloadTimeoutMins))) { result.segmentTimeoutInMs = Number(segmentDownloadTimeoutMins) * 60 * 1000; } debug(`Use Azure SDK: ${result.useAzureSdk}`); debug(`Download concurrency: ${result.downloadConcurrency}`); debug(`Request timeout (ms): ${result.timeoutInMs}`); debug(`Cache segment download timeout mins env var: ${process.env['SEGMENT_DOWNLOAD_TIMEOUT_MINS']}`); debug(`Segment download timeout (ms): ${result.segmentTimeoutInMs}`); debug(`Lookup only: ${result.lookupOnly}`); return result; } function isGhes() { const ghUrl = new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com'); const hostname = ghUrl.hostname.trimEnd().toUpperCase(); const isGitHubHost = hostname === 'GITHUB.COM'; const isGheHost = hostname.endsWith('.GHE.COM'); const isLocalHost = hostname.endsWith('.LOCALHOST'); return !isGitHubHost && !isGheHost && !isLocalHost; } function getCacheServiceVersion() { // Cache service v2 is not supported on GHES. We will default to // cache service v1 even if the feature flag was enabled by user. if (isGhes()) return 'v1'; return process.env['ACTIONS_CACHE_SERVICE_V2'] ? 'v2' : 'v1'; } function getCacheServiceURL() { const version = getCacheServiceVersion(); // Based on the version of the cache service, we will determine which // URL to use. switch (version) { case 'v1': return (process.env['ACTIONS_CACHE_URL'] || process.env['ACTIONS_RESULTS_URL'] || ''); case 'v2': return process.env['ACTIONS_RESULTS_URL'] || ''; default: throw new Error(`Unsupported cache service version: ${version}`); } } var version = "6.0.1"; var require$$0 = { version: version}; var packageVersion; var hasRequiredPackageVersion; function requirePackageVersion () { if (hasRequiredPackageVersion) return packageVersion; hasRequiredPackageVersion = 1; // This file exists as a CommonJS module to read the version from package.json. // In an ESM package, using `require()` directly in .ts files requires disabling // ESLint rules and doesn't work reliably across all Node.js versions. // By keeping this as a .cjs file, we can use require() naturally and export // the version for the ESM modules to import. const packageJson = require$$0; packageVersion = { version: packageJson.version }; return packageVersion; } var packageVersionExports = requirePackageVersion(); /** * Ensure that this User Agent String is used in all HTTP calls so that we can monitor telemetry between different versions of this package */ function getUserAgentString() { return `@actions/cache-${packageVersionExports.version}`; } var __awaiter$3 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; function getCacheApiUrl(resource) { const baseUrl = getCacheServiceURL(); if (!baseUrl) { throw new Error('Cache Service Url not found, unable to restore cache.'); } const url = `${baseUrl}_apis/artifactcache/${resource}`; debug(`Resource Url: ${url}`); return url; } function createAcceptHeader(type, apiVersion) { return `${type};api-version=${apiVersion}`; } function getRequestOptions() { const requestOptions = { headers: { Accept: createAcceptHeader('application/json', '6.0-preview.1') } }; return requestOptions; } function createHttpClient() { const token = process.env['ACTIONS_RUNTIME_TOKEN'] || ''; const bearerCredentialHandler = new BearerCredentialHandler(token); return new HttpClient(getUserAgentString(), [bearerCredentialHandler], getRequestOptions()); } function getCacheEntry(keys, paths, options) { return __awaiter$3(this, void 0, void 0, function* () { const httpClient = createHttpClient(); const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive); const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`; const response = yield retryTypedResponse('getCacheEntry', () => __awaiter$3(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); })); // Cache not found if (response.statusCode === 204) { // List cache for primary key only if cache miss occurs if (isDebug()) { yield printCachesListForDiagnostics(keys[0], httpClient, version); } return null; } if (!isSuccessStatusCode(response.statusCode)) { throw new Error(`Cache service responded with ${response.statusCode}`); } const cacheResult = response.result; const cacheDownloadUrl = cacheResult === null || cacheResult === void 0 ? void 0 : cacheResult.archiveLocation; if (!cacheDownloadUrl) { // Cache achiveLocation not found. This should never happen, and hence bail out. throw new Error('Cache not found.'); } setSecret(cacheDownloadUrl); debug(`Cache Result:`); debug(JSON.stringify(cacheResult)); return cacheResult; }); } function printCachesListForDiagnostics(key, httpClient, version) { return __awaiter$3(this, void 0, void 0, function* () { const resource = `caches?key=${encodeURIComponent(key)}`; const response = yield retryTypedResponse('listCache', () => __awaiter$3(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); })); if (response.statusCode === 200) { const cacheListResult = response.result; const totalCount = cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.totalCount; if (totalCount && totalCount > 0) { debug(`No matching cache found for cache key '${key}', version '${version} and scope ${process.env['GITHUB_REF']}. There exist one or more cache(s) with similar key but they have different version or scope. See more info on cache matching here: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key \nOther caches with similar key:`); for (const cacheEntry of (cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.artifactCaches) || []) { debug(`Cache Key: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheKey}, Cache Version: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheVersion}, Cache Scope: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.scope}, Cache Created: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.creationTime}`); } } } }); } function downloadCache(archiveLocation, archivePath, options) { return __awaiter$3(this, void 0, void 0, function* () { const archiveUrl = new URL$1(archiveLocation); const downloadOptions = getDownloadOptions(options); if (archiveUrl.hostname.endsWith('.blob.core.windows.net')) { if (downloadOptions.useAzureSdk) { // Use Azure storage SDK to download caches hosted on Azure to improve speed and reliability. yield downloadCacheStorageSDK(archiveLocation, archivePath, downloadOptions); } else if (downloadOptions.concurrentBlobDownloads) { // Use concurrent implementation with HttpClient to work around blob SDK issue yield downloadCacheHttpClientConcurrent(archiveLocation, archivePath, downloadOptions); } else { // Otherwise, download using the Actions http-client. yield downloadCacheHttpClient(archiveLocation, archivePath); } } else { yield downloadCacheHttpClient(archiveLocation, archivePath); } }); } // Reserve Cache function reserveCache(key, paths, options) { return __awaiter$3(this, void 0, void 0, function* () { const httpClient = createHttpClient(); const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive); const reserveCacheRequest = { key, version, cacheSize: options === null || options === void 0 ? void 0 : options.cacheSize }; const response = yield retryTypedResponse('reserveCache', () => __awaiter$3(this, void 0, void 0, function* () { return httpClient.postJson(getCacheApiUrl('caches'), reserveCacheRequest); })); return response; }); } function getContentRange(start, end) { // Format: `bytes start-end/filesize // start and end are inclusive // filesize can be * // For a 200 byte chunk starting at byte 0: // Content-Range: bytes 0-199/* return `bytes ${start}-${end}/*`; } function uploadChunk(httpClient, resourceUrl, openStream, start, end) { return __awaiter$3(this, void 0, void 0, function* () { debug(`Uploading chunk of size ${end - start + 1} bytes at offset ${start} with content range: ${getContentRange(start, end)}`); const additionalHeaders = { 'Content-Type': 'application/octet-stream', 'Content-Range': getContentRange(start, end) }; const uploadChunkResponse = yield retryHttpClientResponse(`uploadChunk (start: ${start}, end: ${end})`, () => __awaiter$3(this, void 0, void 0, function* () { return httpClient.sendStream('PATCH', resourceUrl, openStream(), additionalHeaders); })); if (!isSuccessStatusCode(uploadChunkResponse.message.statusCode)) { throw new Error(`Cache service responded with ${uploadChunkResponse.message.statusCode} during upload chunk.`); } }); } function uploadFile(httpClient, cacheId, archivePath, options) { return __awaiter$3(this, void 0, void 0, function* () { // Upload Chunks const fileSize = getArchiveFileSizeInBytes(archivePath); const resourceUrl = getCacheApiUrl(`caches/${cacheId.toString()}`); const fd = fs.openSync(archivePath, 'r'); const uploadOptions = getUploadOptions(options); const concurrency = assertDefined('uploadConcurrency', uploadOptions.uploadConcurrency); const maxChunkSize = assertDefined('uploadChunkSize', uploadOptions.uploadChunkSize); const parallelUploads = [...new Array(concurrency).keys()]; debug('Awaiting all uploads'); let offset = 0; try { yield Promise.all(parallelUploads.map(() => __awaiter$3(this, void 0, void 0, function* () { while (offset < fileSize) { const chunkSize = Math.min(fileSize - offset, maxChunkSize); const start = offset; const end = offset + chunkSize - 1; offset += maxChunkSize; yield uploadChunk(httpClient, resourceUrl, () => fs .createReadStream(archivePath, { fd, start, end, autoClose: false }) .on('error', error => { throw new Error(`Cache upload failed because file read failed with ${error.message}`); }), start, end); } }))); } finally { fs.closeSync(fd); } return; }); } function commitCache(httpClient, cacheId, filesize) { return __awaiter$3(this, void 0, void 0, function* () { const commitCacheRequest = { size: filesize }; return yield retryTypedResponse('commitCache', () => __awaiter$3(this, void 0, void 0, function* () { return httpClient.postJson(getCacheApiUrl(`caches/${cacheId.toString()}`), commitCacheRequest); })); }); } function saveCache$1(cacheId, archivePath, signedUploadURL, options) { return __awaiter$3(this, void 0, void 0, function* () { const uploadOptions = getUploadOptions(options); if (uploadOptions.useAzureSdk) { // Use Azure storage SDK to upload caches directly to Azure if (!signedUploadURL) { throw new Error('Azure Storage SDK can only be used when a signed URL is provided.'); } yield uploadCacheArchiveSDK(signedUploadURL, archivePath, options); } else { const httpClient = createHttpClient(); debug('Upload cache'); yield uploadFile(httpClient, cacheId, archivePath, options); // Commit Cache debug('Commiting cache'); const cacheSize = getArchiveFileSizeInBytes(archivePath); info(`Cache Size: ~${Math.round(cacheSize / (1024 * 1024))} MB (${cacheSize} B)`); const commitCacheResponse = yield commitCache(httpClient, cacheId, cacheSize); if (!isSuccessStatusCode(commitCacheResponse.statusCode)) { throw new Error(`Cache service responded with ${commitCacheResponse.statusCode} during commit cache.`); } info('Cache saved successfully'); } }); } /** * Get the type of a JSON value. * Distinguishes between array, null and object. */ function typeofJsonValue(value) { let t = typeof value; if (t == "object") { if (Array.isArray(value)) return "array"; if (value === null) return "null"; } return t; } /** * Is this a JSON object (instead of an array or null)? */ function isJsonObject(value) { return value !== null && typeof value == "object" && !Array.isArray(value); } // lookup table from base64 character to byte let encTable = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); // lookup table from base64 character *code* to byte because lookup by number is fast let decTable = []; for (let i = 0; i < encTable.length; i++) decTable[encTable[i].charCodeAt(0)] = i; // support base64url variants decTable["-".charCodeAt(0)] = encTable.indexOf("+"); decTable["_".charCodeAt(0)] = encTable.indexOf("/"); /** * Decodes a base64 string to a byte array. * * - ignores white-space, including line breaks and tabs * - allows inner padding (can decode concatenated base64 strings) * - does not require padding * - understands base64url encoding: * "-" instead of "+", * "_" instead of "/", * no padding */ function base64decode(base64Str) { // estimate byte size, not accounting for inner padding and whitespace let es = base64Str.length * 3 / 4; // if (es % 3 !== 0) // throw new Error('invalid base64 string'); if (base64Str[base64Str.length - 2] == '=') es -= 2; else if (base64Str[base64Str.length - 1] == '=') es -= 1; let bytes = new Uint8Array(es), bytePos = 0, // position in byte array groupPos = 0, // position in base64 group b, // current byte p = 0 // previous byte ; for (let i = 0; i < base64Str.length; i++) { b = decTable[base64Str.charCodeAt(i)]; if (b === undefined) { // noinspection FallThroughInSwitchStatementJS switch (base64Str[i]) { case '=': groupPos = 0; // reset state when padding found case '\n': case '\r': case '\t': case ' ': continue; // skip white-space, and padding default: throw Error(`invalid base64 string.`); } } switch (groupPos) { case 0: p = b; groupPos = 1; break; case 1: bytes[bytePos++] = p << 2 | (b & 48) >> 4; p = b; groupPos = 2; break; case 2: bytes[bytePos++] = (p & 15) << 4 | (b & 60) >> 2; p = b; groupPos = 3; break; case 3: bytes[bytePos++] = (p & 3) << 6 | b; groupPos = 0; break; } } if (groupPos == 1) throw Error(`invalid base64 string.`); return bytes.subarray(0, bytePos); } /** * Encodes a byte array to a base64 string. * Adds padding at the end. * Does not insert newlines. */ function base64encode(bytes) { let base64 = '', groupPos = 0, // position in base64 group b, // current byte p = 0; // carry over from previous byte for (let i = 0; i < bytes.length; i++) { b = bytes[i]; switch (groupPos) { case 0: base64 += encTable[b >> 2]; p = (b & 3) << 4; groupPos = 1; break; case 1: base64 += encTable[p | b >> 4]; p = (b & 15) << 2; groupPos = 2; break; case 2: base64 += encTable[p | b >> 6]; base64 += encTable[b & 63]; groupPos = 0; break; } } // padding required? if (groupPos) { base64 += encTable[p]; base64 += '='; if (groupPos == 1) base64 += '='; } return base64; } /** * This handler implements the default behaviour for unknown fields. * When reading data, unknown fields are stored on the message, in a * symbol property. * When writing data, the symbol property is queried and unknown fields * are serialized into the output again. */ var UnknownFieldHandler; (function (UnknownFieldHandler) { /** * The symbol used to store unknown fields for a message. * The property must conform to `UnknownFieldContainer`. */ UnknownFieldHandler.symbol = Symbol.for("protobuf-ts/unknown"); /** * Store an unknown field during binary read directly on the message. * This method is compatible with `BinaryReadOptions.readUnknownField`. */ UnknownFieldHandler.onRead = (typeName, message, fieldNo, wireType, data) => { let container = is(message) ? message[UnknownFieldHandler.symbol] : message[UnknownFieldHandler.symbol] = []; container.push({ no: fieldNo, wireType, data }); }; /** * Write unknown fields stored for the message to the writer. * This method is compatible with `BinaryWriteOptions.writeUnknownFields`. */ UnknownFieldHandler.onWrite = (typeName, message, writer) => { for (let { no, wireType, data } of UnknownFieldHandler.list(message)) writer.tag(no, wireType).raw(data); }; /** * List unknown fields stored for the message. * Note that there may be multiples fields with the same number. */ UnknownFieldHandler.list = (message, fieldNo) => { if (is(message)) { let all = message[UnknownFieldHandler.symbol]; return fieldNo ? all.filter(uf => uf.no == fieldNo) : all; } return []; }; /** * Returns the last unknown field by field number. */ UnknownFieldHandler.last = (message, fieldNo) => UnknownFieldHandler.list(message, fieldNo).slice(-1)[0]; const is = (message) => message && Array.isArray(message[UnknownFieldHandler.symbol]); })(UnknownFieldHandler || (UnknownFieldHandler = {})); /** * Protobuf binary format wire types. * * A wire type provides just enough information to find the length of the * following value. * * See https://developers.google.com/protocol-buffers/docs/encoding#structure */ var WireType; (function (WireType) { /** * Used for int32, int64, uint32, uint64, sint32, sint64, bool, enum */ WireType[WireType["Varint"] = 0] = "Varint"; /** * Used for fixed64, sfixed64, double. * Always 8 bytes with little-endian byte order. */ WireType[WireType["Bit64"] = 1] = "Bit64"; /** * Used for string, bytes, embedded messages, packed repeated fields * * Only repeated numeric types (types which use the varint, 32-bit, * or 64-bit wire types) can be packed. In proto3, such fields are * packed by default. */ WireType[WireType["LengthDelimited"] = 2] = "LengthDelimited"; /** * Used for groups * @deprecated */ WireType[WireType["StartGroup"] = 3] = "StartGroup"; /** * Used for groups * @deprecated */ WireType[WireType["EndGroup"] = 4] = "EndGroup"; /** * Used for fixed32, sfixed32, float. * Always 4 bytes with little-endian byte order. */ WireType[WireType["Bit32"] = 5] = "Bit32"; })(WireType || (WireType = {})); // Copyright 2008 Google Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Code generated by the Protocol Buffer compiler is owned by the owner // of the input file used when generating it. This code is not // standalone and requires a support library to be linked with it. This // support library is itself covered by the above license. /** * Read a 64 bit varint as two JS numbers. * * Returns tuple: * [0]: low bits * [0]: high bits * * Copyright 2008 Google Inc. All rights reserved. * * See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/buffer_decoder.js#L175 */ function varint64read() { let lowBits = 0; let highBits = 0; for (let shift = 0; shift < 28; shift += 7) { let b = this.buf[this.pos++]; lowBits |= (b & 0x7F) << shift; if ((b & 0x80) == 0) { this.assertBounds(); return [lowBits, highBits]; } } let middleByte = this.buf[this.pos++]; // last four bits of the first 32 bit number lowBits |= (middleByte & 0x0F) << 28; // 3 upper bits are part of the next 32 bit number highBits = (middleByte & 0x70) >> 4; if ((middleByte & 0x80) == 0) { this.assertBounds(); return [lowBits, highBits]; } for (let shift = 3; shift <= 31; shift += 7) { let b = this.buf[this.pos++]; highBits |= (b & 0x7F) << shift; if ((b & 0x80) == 0) { this.assertBounds(); return [lowBits, highBits]; } } throw new Error('invalid varint'); } /** * Write a 64 bit varint, given as two JS numbers, to the given bytes array. * * Copyright 2008 Google Inc. All rights reserved. * * See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/writer.js#L344 */ function varint64write(lo, hi, bytes) { for (let i = 0; i < 28; i = i + 7) { const shift = lo >>> i; const hasNext = !((shift >>> 7) == 0 && hi == 0); const byte = (hasNext ? shift | 0x80 : shift) & 0xFF; bytes.push(byte); if (!hasNext) { return; } } const splitBits = ((lo >>> 28) & 0x0F) | ((hi & 0x07) << 4); const hasMoreBits = !((hi >> 3) == 0); bytes.push((hasMoreBits ? splitBits | 0x80 : splitBits) & 0xFF); if (!hasMoreBits) { return; } for (let i = 3; i < 31; i = i + 7) { const shift = hi >>> i; const hasNext = !((shift >>> 7) == 0); const byte = (hasNext ? shift | 0x80 : shift) & 0xFF; bytes.push(byte); if (!hasNext) { return; } } bytes.push((hi >>> 31) & 0x01); } // constants for binary math const TWO_PWR_32_DBL$1 = (1 << 16) * (1 << 16); /** * Parse decimal string of 64 bit integer value as two JS numbers. * * Returns tuple: * [0]: minus sign? * [1]: low bits * [2]: high bits * * Copyright 2008 Google Inc. */ function int64fromString(dec) { // Check for minus sign. let minus = dec[0] == '-'; if (minus) dec = dec.slice(1); // Work 6 decimal digits at a time, acting like we're converting base 1e6 // digits to binary. This is safe to do with floating point math because // Number.isSafeInteger(ALL_32_BITS * 1e6) == true. const base = 1e6; let lowBits = 0; let highBits = 0; function add1e6digit(begin, end) { // Note: Number('') is 0. const digit1e6 = Number(dec.slice(begin, end)); highBits *= base; lowBits = lowBits * base + digit1e6; // Carry bits from lowBits to highBits if (lowBits >= TWO_PWR_32_DBL$1) { highBits = highBits + ((lowBits / TWO_PWR_32_DBL$1) | 0); lowBits = lowBits % TWO_PWR_32_DBL$1; } } add1e6digit(-24, -18); add1e6digit(-18, -12); add1e6digit(-12, -6); add1e6digit(-6); return [minus, lowBits, highBits]; } /** * Format 64 bit integer value (as two JS numbers) to decimal string. * * Copyright 2008 Google Inc. */ function int64toString(bitsLow, bitsHigh) { // Skip the expensive conversion if the number is small enough to use the // built-in conversions. if ((bitsHigh >>> 0) <= 0x1FFFFF) { return '' + (TWO_PWR_32_DBL$1 * bitsHigh + (bitsLow >>> 0)); } // What this code is doing is essentially converting the input number from // base-2 to base-1e7, which allows us to represent the 64-bit range with // only 3 (very large) digits. Those digits are then trivial to convert to // a base-10 string. // The magic numbers used here are - // 2^24 = 16777216 = (1,6777216) in base-1e7. // 2^48 = 281474976710656 = (2,8147497,6710656) in base-1e7. // Split 32:32 representation into 16:24:24 representation so our // intermediate digits don't overflow. let low = bitsLow & 0xFFFFFF; let mid = (((bitsLow >>> 24) | (bitsHigh << 8)) >>> 0) & 0xFFFFFF; let high = (bitsHigh >> 16) & 0xFFFF; // Assemble our three base-1e7 digits, ignoring carries. The maximum // value in a digit at this step is representable as a 48-bit integer, which // can be stored in a 64-bit floating point number. let digitA = low + (mid * 6777216) + (high * 6710656); let digitB = mid + (high * 8147497); let digitC = (high * 2); // Apply carries from A to B and from B to C. let base = 10000000; if (digitA >= base) { digitB += Math.floor(digitA / base); digitA %= base; } if (digitB >= base) { digitC += Math.floor(digitB / base); digitB %= base; } // Convert base-1e7 digits to base-10, with optional leading zeroes. function decimalFrom1e7(digit1e7, needLeadingZeros) { let partial = digit1e7 ? String(digit1e7) : ''; if (needLeadingZeros) { return '0000000'.slice(partial.length) + partial; } return partial; } return decimalFrom1e7(digitC, /*needLeadingZeros=*/ 0) + decimalFrom1e7(digitB, /*needLeadingZeros=*/ digitC) + // If the final 1e7 digit didn't need leading zeros, we would have // returned via the trivial code path at the top. decimalFrom1e7(digitA, /*needLeadingZeros=*/ 1); } /** * Write a 32 bit varint, signed or unsigned. Same as `varint64write(0, value, bytes)` * * Copyright 2008 Google Inc. All rights reserved. * * See https://github.com/protocolbuffers/protobuf/blob/1b18833f4f2a2f681f4e4a25cdf3b0a43115ec26/js/binary/encoder.js#L144 */ function varint32write(value, bytes) { if (value >= 0) { // write value as varint 32 while (value > 0x7f) { bytes.push((value & 0x7f) | 0x80); value = value >>> 7; } bytes.push(value); } else { for (let i = 0; i < 9; i++) { bytes.push(value & 127 | 128); value = value >> 7; } bytes.push(1); } } /** * Read an unsigned 32 bit varint. * * See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/buffer_decoder.js#L220 */ function varint32read() { let b = this.buf[this.pos++]; let result = b & 0x7F; if ((b & 0x80) == 0) { this.assertBounds(); return result; } b = this.buf[this.pos++]; result |= (b & 0x7F) << 7; if ((b & 0x80) == 0) { this.assertBounds(); return result; } b = this.buf[this.pos++]; result |= (b & 0x7F) << 14; if ((b & 0x80) == 0) { this.assertBounds(); return result; } b = this.buf[this.pos++]; result |= (b & 0x7F) << 21; if ((b & 0x80) == 0) { this.assertBounds(); return result; } // Extract only last 4 bits b = this.buf[this.pos++]; result |= (b & 0x0F) << 28; for (let readBytes = 5; ((b & 0x80) !== 0) && readBytes < 10; readBytes++) b = this.buf[this.pos++]; if ((b & 0x80) != 0) throw new Error('invalid varint'); this.assertBounds(); // Result can have 32 bits, convert it to unsigned return result >>> 0; } let BI; function detectBi() { const dv = new DataView(new ArrayBuffer(8)); const ok = globalThis.BigInt !== undefined && typeof dv.getBigInt64 === "function" && typeof dv.getBigUint64 === "function" && typeof dv.setBigInt64 === "function" && typeof dv.setBigUint64 === "function"; BI = ok ? { MIN: BigInt("-9223372036854775808"), MAX: BigInt("9223372036854775807"), UMIN: BigInt("0"), UMAX: BigInt("18446744073709551615"), C: BigInt, V: dv, } : undefined; } detectBi(); function assertBi(bi) { if (!bi) throw new Error("BigInt unavailable, see https://github.com/timostamm/protobuf-ts/blob/v1.0.8/MANUAL.md#bigint-support"); } // used to validate from(string) input (when bigint is unavailable) const RE_DECIMAL_STR = /^-?[0-9]+$/; // constants for binary math const TWO_PWR_32_DBL = 0x100000000; const HALF_2_PWR_32 = 0x080000000; // base class for PbLong and PbULong provides shared code class SharedPbLong { /** * Create a new instance with the given bits. */ constructor(lo, hi) { this.lo = lo | 0; this.hi = hi | 0; } /** * Is this instance equal to 0? */ isZero() { return this.lo == 0 && this.hi == 0; } /** * Convert to a native number. */ toNumber() { let result = this.hi * TWO_PWR_32_DBL + (this.lo >>> 0); if (!Number.isSafeInteger(result)) throw new Error("cannot convert to safe number"); return result; } } /** * 64-bit unsigned integer as two 32-bit values. * Converts between `string`, `number` and `bigint` representations. */ class PbULong extends SharedPbLong { /** * Create instance from a `string`, `number` or `bigint`. */ static from(value) { if (BI) // noinspection FallThroughInSwitchStatementJS switch (typeof value) { case "string": if (value == "0") return this.ZERO; if (value == "") throw new Error('string is no integer'); value = BI.C(value); case "number": if (value === 0) return this.ZERO; value = BI.C(value); case "bigint": if (!value) return this.ZERO; if (value < BI.UMIN) throw new Error('signed value for ulong'); if (value > BI.UMAX) throw new Error('ulong too large'); BI.V.setBigUint64(0, value, true); return new PbULong(BI.V.getInt32(0, true), BI.V.getInt32(4, true)); } else switch (typeof value) { case "string": if (value == "0") return this.ZERO; value = value.trim(); if (!RE_DECIMAL_STR.test(value)) throw new Error('string is no integer'); let [minus, lo, hi] = int64fromString(value); if (minus) throw new Error('signed value for ulong'); return new PbULong(lo, hi); case "number": if (value == 0) return this.ZERO; if (!Number.isSafeInteger(value)) throw new Error('number is no integer'); if (value < 0) throw new Error('signed value for ulong'); return new PbULong(value, value / TWO_PWR_32_DBL); } throw new Error('unknown value ' + typeof value); } /** * Convert to decimal string. */ toString() { return BI ? this.toBigInt().toString() : int64toString(this.lo, this.hi); } /** * Convert to native bigint. */ toBigInt() { assertBi(BI); BI.V.setInt32(0, this.lo, true); BI.V.setInt32(4, this.hi, true); return BI.V.getBigUint64(0, true); } } /** * ulong 0 singleton. */ PbULong.ZERO = new PbULong(0, 0); /** * 64-bit signed integer as two 32-bit values. * Converts between `string`, `number` and `bigint` representations. */ class PbLong extends SharedPbLong { /** * Create instance from a `string`, `number` or `bigint`. */ static from(value) { if (BI) // noinspection FallThroughInSwitchStatementJS switch (typeof value) { case "string": if (value == "0") return this.ZERO; if (value == "") throw new Error('string is no integer'); value = BI.C(value); case "number": if (value === 0) return this.ZERO; value = BI.C(value); case "bigint": if (!value) return this.ZERO; if (value < BI.MIN) throw new Error('signed long too small'); if (value > BI.MAX) throw new Error('signed long too large'); BI.V.setBigInt64(0, value, true); return new PbLong(BI.V.getInt32(0, true), BI.V.getInt32(4, true)); } else switch (typeof value) { case "string": if (value == "0") return this.ZERO; value = value.trim(); if (!RE_DECIMAL_STR.test(value)) throw new Error('string is no integer'); let [minus, lo, hi] = int64fromString(value); if (minus) { if (hi > HALF_2_PWR_32 || (hi == HALF_2_PWR_32 && lo != 0)) throw new Error('signed long too small'); } else if (hi >= HALF_2_PWR_32) throw new Error('signed long too large'); let pbl = new PbLong(lo, hi); return minus ? pbl.negate() : pbl; case "number": if (value == 0) return this.ZERO; if (!Number.isSafeInteger(value)) throw new Error('number is no integer'); return value > 0 ? new PbLong(value, value / TWO_PWR_32_DBL) : new PbLong(-value, -value / TWO_PWR_32_DBL).negate(); } throw new Error('unknown value ' + typeof value); } /** * Do we have a minus sign? */ isNegative() { return (this.hi & HALF_2_PWR_32) !== 0; } /** * Negate two's complement. * Invert all the bits and add one to the result. */ negate() { let hi = ~this.hi, lo = this.lo; if (lo) lo = ~lo + 1; else hi += 1; return new PbLong(lo, hi); } /** * Convert to decimal string. */ toString() { if (BI) return this.toBigInt().toString(); if (this.isNegative()) { let n = this.negate(); return '-' + int64toString(n.lo, n.hi); } return int64toString(this.lo, this.hi); } /** * Convert to native bigint. */ toBigInt() { assertBi(BI); BI.V.setInt32(0, this.lo, true); BI.V.setInt32(4, this.hi, true); return BI.V.getBigInt64(0, true); } } /** * long 0 singleton. */ PbLong.ZERO = new PbLong(0, 0); const defaultsRead$1 = { readUnknownField: true, readerFactory: bytes => new BinaryReader(bytes), }; /** * Make options for reading binary data form partial options. */ function binaryReadOptions(options) { return options ? Object.assign(Object.assign({}, defaultsRead$1), options) : defaultsRead$1; } class BinaryReader { constructor(buf, textDecoder) { this.varint64 = varint64read; // dirty cast for `this` /** * Read a `uint32` field, an unsigned 32 bit varint. */ this.uint32 = varint32read; // dirty cast for `this` and access to protected `buf` this.buf = buf; this.len = buf.length; this.pos = 0; this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); this.textDecoder = textDecoder !== null && textDecoder !== void 0 ? textDecoder : new TextDecoder("utf-8", { fatal: true, ignoreBOM: true, }); } /** * Reads a tag - field number and wire type. */ tag() { let tag = this.uint32(), fieldNo = tag >>> 3, wireType = tag & 7; if (fieldNo <= 0 || wireType < 0 || wireType > 5) throw new Error("illegal tag: field no " + fieldNo + " wire type " + wireType); return [fieldNo, wireType]; } /** * Skip one element on the wire and return the skipped data. * Supports WireType.StartGroup since v2.0.0-alpha.23. */ skip(wireType) { let start = this.pos; // noinspection FallThroughInSwitchStatementJS switch (wireType) { case WireType.Varint: while (this.buf[this.pos++] & 0x80) { // ignore } break; case WireType.Bit64: this.pos += 4; case WireType.Bit32: this.pos += 4; break; case WireType.LengthDelimited: let len = this.uint32(); this.pos += len; break; case WireType.StartGroup: // From descriptor.proto: Group type is deprecated, not supported in proto3. // But we must still be able to parse and treat as unknown. let t; while ((t = this.tag()[1]) !== WireType.EndGroup) { this.skip(t); } break; default: throw new Error("cant skip wire type " + wireType); } this.assertBounds(); return this.buf.subarray(start, this.pos); } /** * Throws error if position in byte array is out of range. */ assertBounds() { if (this.pos > this.len) throw new RangeError("premature EOF"); } /** * Read a `int32` field, a signed 32 bit varint. */ int32() { return this.uint32() | 0; } /** * Read a `sint32` field, a signed, zigzag-encoded 32-bit varint. */ sint32() { let zze = this.uint32(); // decode zigzag return (zze >>> 1) ^ -(zze & 1); } /** * Read a `int64` field, a signed 64-bit varint. */ int64() { return new PbLong(...this.varint64()); } /** * Read a `uint64` field, an unsigned 64-bit varint. */ uint64() { return new PbULong(...this.varint64()); } /** * Read a `sint64` field, a signed, zig-zag-encoded 64-bit varint. */ sint64() { let [lo, hi] = this.varint64(); // decode zig zag let s = -(lo & 1); lo = ((lo >>> 1 | (hi & 1) << 31) ^ s); hi = (hi >>> 1 ^ s); return new PbLong(lo, hi); } /** * Read a `bool` field, a variant. */ bool() { let [lo, hi] = this.varint64(); return lo !== 0 || hi !== 0; } /** * Read a `fixed32` field, an unsigned, fixed-length 32-bit integer. */ fixed32() { return this.view.getUint32((this.pos += 4) - 4, true); } /** * Read a `sfixed32` field, a signed, fixed-length 32-bit integer. */ sfixed32() { return this.view.getInt32((this.pos += 4) - 4, true); } /** * Read a `fixed64` field, an unsigned, fixed-length 64 bit integer. */ fixed64() { return new PbULong(this.sfixed32(), this.sfixed32()); } /** * Read a `fixed64` field, a signed, fixed-length 64-bit integer. */ sfixed64() { return new PbLong(this.sfixed32(), this.sfixed32()); } /** * Read a `float` field, 32-bit floating point number. */ float() { return this.view.getFloat32((this.pos += 4) - 4, true); } /** * Read a `double` field, a 64-bit floating point number. */ double() { return this.view.getFloat64((this.pos += 8) - 8, true); } /** * Read a `bytes` field, length-delimited arbitrary data. */ bytes() { let len = this.uint32(); let start = this.pos; this.pos += len; this.assertBounds(); return this.buf.subarray(start, start + len); } /** * Read a `string` field, length-delimited data converted to UTF-8 text. */ string() { return this.textDecoder.decode(this.bytes()); } } /** * assert that condition is true or throw error (with message) */ function assert(condition, msg) { if (!condition) { throw new Error(msg); } } const FLOAT32_MAX = 3.4028234663852886e+38, FLOAT32_MIN = -34028234663852886e22, UINT32_MAX = 0xFFFFFFFF, INT32_MAX = 0X7FFFFFFF, INT32_MIN = -2147483648; function assertInt32(arg) { if (typeof arg !== "number") throw new Error('invalid int 32: ' + typeof arg); if (!Number.isInteger(arg) || arg > INT32_MAX || arg < INT32_MIN) throw new Error('invalid int 32: ' + arg); } function assertUInt32(arg) { if (typeof arg !== "number") throw new Error('invalid uint 32: ' + typeof arg); if (!Number.isInteger(arg) || arg > UINT32_MAX || arg < 0) throw new Error('invalid uint 32: ' + arg); } function assertFloat32(arg) { if (typeof arg !== "number") throw new Error('invalid float 32: ' + typeof arg); if (!Number.isFinite(arg)) return; if (arg > FLOAT32_MAX || arg < FLOAT32_MIN) throw new Error('invalid float 32: ' + arg); } const defaultsWrite$1 = { writeUnknownFields: true, writerFactory: () => new BinaryWriter(), }; /** * Make options for writing binary data form partial options. */ function binaryWriteOptions(options) { return options ? Object.assign(Object.assign({}, defaultsWrite$1), options) : defaultsWrite$1; } class BinaryWriter { constructor(textEncoder) { /** * Previous fork states. */ this.stack = []; this.textEncoder = textEncoder !== null && textEncoder !== void 0 ? textEncoder : new TextEncoder(); this.chunks = []; this.buf = []; } /** * Return all bytes written and reset this writer. */ finish() { this.chunks.push(new Uint8Array(this.buf)); // flush the buffer let len = 0; for (let i = 0; i < this.chunks.length; i++) len += this.chunks[i].length; let bytes = new Uint8Array(len); let offset = 0; for (let i = 0; i < this.chunks.length; i++) { bytes.set(this.chunks[i], offset); offset += this.chunks[i].length; } this.chunks = []; return bytes; } /** * Start a new fork for length-delimited data like a message * or a packed repeated field. * * Must be joined later with `join()`. */ fork() { this.stack.push({ chunks: this.chunks, buf: this.buf }); this.chunks = []; this.buf = []; return this; } /** * Join the last fork. Write its length and bytes, then * return to the previous state. */ join() { // get chunk of fork let chunk = this.finish(); // restore previous state let prev = this.stack.pop(); if (!prev) throw new Error('invalid state, fork stack empty'); this.chunks = prev.chunks; this.buf = prev.buf; // write length of chunk as varint this.uint32(chunk.byteLength); return this.raw(chunk); } /** * Writes a tag (field number and wire type). * * Equivalent to `uint32( (fieldNo << 3 | type) >>> 0 )`. * * Generated code should compute the tag ahead of time and call `uint32()`. */ tag(fieldNo, type) { return this.uint32((fieldNo << 3 | type) >>> 0); } /** * Write a chunk of raw bytes. */ raw(chunk) { if (this.buf.length) { this.chunks.push(new Uint8Array(this.buf)); this.buf = []; } this.chunks.push(chunk); return this; } /** * Write a `uint32` value, an unsigned 32 bit varint. */ uint32(value) { assertUInt32(value); // write value as varint 32, inlined for speed while (value > 0x7f) { this.buf.push((value & 0x7f) | 0x80); value = value >>> 7; } this.buf.push(value); return this; } /** * Write a `int32` value, a signed 32 bit varint. */ int32(value) { assertInt32(value); varint32write(value, this.buf); return this; } /** * Write a `bool` value, a variant. */ bool(value) { this.buf.push(value ? 1 : 0); return this; } /** * Write a `bytes` value, length-delimited arbitrary data. */ bytes(value) { this.uint32(value.byteLength); // write length of chunk as varint return this.raw(value); } /** * Write a `string` value, length-delimited data converted to UTF-8 text. */ string(value) { let chunk = this.textEncoder.encode(value); this.uint32(chunk.byteLength); // write length of chunk as varint return this.raw(chunk); } /** * Write a `float` value, 32-bit floating point number. */ float(value) { assertFloat32(value); let chunk = new Uint8Array(4); new DataView(chunk.buffer).setFloat32(0, value, true); return this.raw(chunk); } /** * Write a `double` value, a 64-bit floating point number. */ double(value) { let chunk = new Uint8Array(8); new DataView(chunk.buffer).setFloat64(0, value, true); return this.raw(chunk); } /** * Write a `fixed32` value, an unsigned, fixed-length 32-bit integer. */ fixed32(value) { assertUInt32(value); let chunk = new Uint8Array(4); new DataView(chunk.buffer).setUint32(0, value, true); return this.raw(chunk); } /** * Write a `sfixed32` value, a signed, fixed-length 32-bit integer. */ sfixed32(value) { assertInt32(value); let chunk = new Uint8Array(4); new DataView(chunk.buffer).setInt32(0, value, true); return this.raw(chunk); } /** * Write a `sint32` value, a signed, zigzag-encoded 32-bit varint. */ sint32(value) { assertInt32(value); // zigzag encode value = ((value << 1) ^ (value >> 31)) >>> 0; varint32write(value, this.buf); return this; } /** * Write a `fixed64` value, a signed, fixed-length 64-bit integer. */ sfixed64(value) { let chunk = new Uint8Array(8); let view = new DataView(chunk.buffer); let long = PbLong.from(value); view.setInt32(0, long.lo, true); view.setInt32(4, long.hi, true); return this.raw(chunk); } /** * Write a `fixed64` value, an unsigned, fixed-length 64 bit integer. */ fixed64(value) { let chunk = new Uint8Array(8); let view = new DataView(chunk.buffer); let long = PbULong.from(value); view.setInt32(0, long.lo, true); view.setInt32(4, long.hi, true); return this.raw(chunk); } /** * Write a `int64` value, a signed 64-bit varint. */ int64(value) { let long = PbLong.from(value); varint64write(long.lo, long.hi, this.buf); return this; } /** * Write a `sint64` value, a signed, zig-zag-encoded 64-bit varint. */ sint64(value) { let long = PbLong.from(value), // zigzag encode sign = long.hi >> 31, lo = (long.lo << 1) ^ sign, hi = ((long.hi << 1) | (long.lo >>> 31)) ^ sign; varint64write(lo, hi, this.buf); return this; } /** * Write a `uint64` value, an unsigned 64-bit varint. */ uint64(value) { let long = PbULong.from(value); varint64write(long.lo, long.hi, this.buf); return this; } } const defaultsWrite = { emitDefaultValues: false, enumAsInteger: false, useProtoFieldName: false, prettySpaces: 0, }, defaultsRead = { ignoreUnknownFields: false, }; /** * Make options for reading JSON data from partial options. */ function jsonReadOptions(options) { return options ? Object.assign(Object.assign({}, defaultsRead), options) : defaultsRead; } /** * Make options for writing JSON data from partial options. */ function jsonWriteOptions(options) { return options ? Object.assign(Object.assign({}, defaultsWrite), options) : defaultsWrite; } /** * The symbol used as a key on message objects to store the message type. * * Note that this is an experimental feature - it is here to stay, but * implementation details may change without notice. */ const MESSAGE_TYPE = Symbol.for("protobuf-ts/message-type"); /** * Converts snake_case to lowerCamelCase. * * Should behave like protoc: * https://github.com/protocolbuffers/protobuf/blob/e8ae137c96444ea313485ed1118c5e43b2099cf1/src/google/protobuf/compiler/java/java_helpers.cc#L118 */ function lowerCamelCase(snakeCase) { let capNext = false; const sb = []; for (let i = 0; i < snakeCase.length; i++) { let next = snakeCase.charAt(i); if (next == '_') { capNext = true; } else if (/\d/.test(next)) { sb.push(next); capNext = true; } else if (capNext) { sb.push(next.toUpperCase()); capNext = false; } else if (i == 0) { sb.push(next.toLowerCase()); } else { sb.push(next); } } return sb.join(''); } /** * Scalar value types. This is a subset of field types declared by protobuf * enum google.protobuf.FieldDescriptorProto.Type The types GROUP and MESSAGE * are omitted, but the numerical values are identical. */ var ScalarType; (function (ScalarType) { // 0 is reserved for errors. // Order is weird for historical reasons. ScalarType[ScalarType["DOUBLE"] = 1] = "DOUBLE"; ScalarType[ScalarType["FLOAT"] = 2] = "FLOAT"; // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if // negative values are likely. ScalarType[ScalarType["INT64"] = 3] = "INT64"; ScalarType[ScalarType["UINT64"] = 4] = "UINT64"; // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if // negative values are likely. ScalarType[ScalarType["INT32"] = 5] = "INT32"; ScalarType[ScalarType["FIXED64"] = 6] = "FIXED64"; ScalarType[ScalarType["FIXED32"] = 7] = "FIXED32"; ScalarType[ScalarType["BOOL"] = 8] = "BOOL"; ScalarType[ScalarType["STRING"] = 9] = "STRING"; // Tag-delimited aggregate. // Group type is deprecated and not supported in proto3. However, Proto3 // implementations should still be able to parse the group wire format and // treat group fields as unknown fields. // TYPE_GROUP = 10, // TYPE_MESSAGE = 11, // Length-delimited aggregate. // New in version 2. ScalarType[ScalarType["BYTES"] = 12] = "BYTES"; ScalarType[ScalarType["UINT32"] = 13] = "UINT32"; // TYPE_ENUM = 14, ScalarType[ScalarType["SFIXED32"] = 15] = "SFIXED32"; ScalarType[ScalarType["SFIXED64"] = 16] = "SFIXED64"; ScalarType[ScalarType["SINT32"] = 17] = "SINT32"; ScalarType[ScalarType["SINT64"] = 18] = "SINT64"; })(ScalarType || (ScalarType = {})); /** * JavaScript representation of 64 bit integral types. Equivalent to the * field option "jstype". * * By default, protobuf-ts represents 64 bit types as `bigint`. * * You can change the default behaviour by enabling the plugin parameter * `long_type_string`, which will represent 64 bit types as `string`. * * Alternatively, you can change the behaviour for individual fields * with the field option "jstype": * * ```protobuf * uint64 my_field = 1 [jstype = JS_STRING]; * uint64 other_field = 2 [jstype = JS_NUMBER]; * ``` */ var LongType; (function (LongType) { /** * Use JavaScript `bigint`. * * Field option `[jstype = JS_NORMAL]`. */ LongType[LongType["BIGINT"] = 0] = "BIGINT"; /** * Use JavaScript `string`. * * Field option `[jstype = JS_STRING]`. */ LongType[LongType["STRING"] = 1] = "STRING"; /** * Use JavaScript `number`. * * Large values will loose precision. * * Field option `[jstype = JS_NUMBER]`. */ LongType[LongType["NUMBER"] = 2] = "NUMBER"; })(LongType || (LongType = {})); /** * Protobuf 2.1.0 introduced packed repeated fields. * Setting the field option `[packed = true]` enables packing. * * In proto3, all repeated fields are packed by default. * Setting the field option `[packed = false]` disables packing. * * Packed repeated fields are encoded with a single tag, * then a length-delimiter, then the element values. * * Unpacked repeated fields are encoded with a tag and * value for each element. * * `bytes` and `string` cannot be packed. */ var RepeatType; (function (RepeatType) { /** * The field is not repeated. */ RepeatType[RepeatType["NO"] = 0] = "NO"; /** * The field is repeated and should be packed. * Invalid for `bytes` and `string`, they cannot be packed. */ RepeatType[RepeatType["PACKED"] = 1] = "PACKED"; /** * The field is repeated but should not be packed. * The only valid repeat type for repeated `bytes` and `string`. */ RepeatType[RepeatType["UNPACKED"] = 2] = "UNPACKED"; })(RepeatType || (RepeatType = {})); /** * Turns PartialFieldInfo into FieldInfo. */ function normalizeFieldInfo(field) { var _a, _b, _c, _d; field.localName = (_a = field.localName) !== null && _a !== void 0 ? _a : lowerCamelCase(field.name); field.jsonName = (_b = field.jsonName) !== null && _b !== void 0 ? _b : lowerCamelCase(field.name); field.repeat = (_c = field.repeat) !== null && _c !== void 0 ? _c : RepeatType.NO; field.opt = (_d = field.opt) !== null && _d !== void 0 ? _d : (field.repeat ? false : field.oneof ? false : field.kind == "message"); return field; } /** * Is the given value a valid oneof group? * * We represent protobuf `oneof` as algebraic data types (ADT) in generated * code. But when working with messages of unknown type, the ADT does not * help us. * * This type guard checks if the given object adheres to the ADT rules, which * are as follows: * * 1) Must be an object. * * 2) Must have a "oneofKind" discriminator property. * * 3) If "oneofKind" is `undefined`, no member field is selected. The object * must not have any other properties. * * 4) If "oneofKind" is a `string`, the member field with this name is * selected. * * 5) If a member field is selected, the object must have a second property * with this name. The property must not be `undefined`. * * 6) No extra properties are allowed. The object has either one property * (no selection) or two properties (selection). * */ function isOneofGroup(any) { if (typeof any != 'object' || any === null || !any.hasOwnProperty('oneofKind')) { return false; } switch (typeof any.oneofKind) { case "string": if (any[any.oneofKind] === undefined) return false; return Object.keys(any).length == 2; case "undefined": return Object.keys(any).length == 1; default: return false; } } // noinspection JSMethodCanBeStatic class ReflectionTypeCheck { constructor(info) { var _a; this.fields = (_a = info.fields) !== null && _a !== void 0 ? _a : []; } prepare() { if (this.data) return; const req = [], known = [], oneofs = []; for (let field of this.fields) { if (field.oneof) { if (!oneofs.includes(field.oneof)) { oneofs.push(field.oneof); req.push(field.oneof); known.push(field.oneof); } } else { known.push(field.localName); switch (field.kind) { case "scalar": case "enum": if (!field.opt || field.repeat) req.push(field.localName); break; case "message": if (field.repeat) req.push(field.localName); break; case "map": req.push(field.localName); break; } } } this.data = { req, known, oneofs: Object.values(oneofs) }; } /** * Is the argument a valid message as specified by the * reflection information? * * Checks all field types recursively. The `depth` * specifies how deep into the structure the check will be. * * With a depth of 0, only the presence of fields * is checked. * * With a depth of 1 or more, the field types are checked. * * With a depth of 2 or more, the members of map, repeated * and message fields are checked. * * Message fields will be checked recursively with depth - 1. * * The number of map entries / repeated values being checked * is < depth. */ is(message, depth, allowExcessProperties = false) { if (depth < 0) return true; if (message === null || message === undefined || typeof message != 'object') return false; this.prepare(); let keys = Object.keys(message), data = this.data; // if a required field is missing in arg, this cannot be a T if (keys.length < data.req.length || data.req.some(n => !keys.includes(n))) return false; if (!allowExcessProperties) { // if the arg contains a key we dont know, this is not a literal T if (keys.some(k => !data.known.includes(k))) return false; } // "With a depth of 0, only the presence and absence of fields is checked." // "With a depth of 1 or more, the field types are checked." if (depth < 1) { return true; } // check oneof group for (const name of data.oneofs) { const group = message[name]; if (!isOneofGroup(group)) return false; if (group.oneofKind === undefined) continue; const field = this.fields.find(f => f.localName === group.oneofKind); if (!field) return false; // we found no field, but have a kind, something is wrong if (!this.field(group[group.oneofKind], field, allowExcessProperties, depth)) return false; } // check types for (const field of this.fields) { if (field.oneof !== undefined) continue; if (!this.field(message[field.localName], field, allowExcessProperties, depth)) return false; } return true; } field(arg, field, allowExcessProperties, depth) { let repeated = field.repeat; switch (field.kind) { case "scalar": if (arg === undefined) return field.opt; if (repeated) return this.scalars(arg, field.T, depth, field.L); return this.scalar(arg, field.T, field.L); case "enum": if (arg === undefined) return field.opt; if (repeated) return this.scalars(arg, ScalarType.INT32, depth); return this.scalar(arg, ScalarType.INT32); case "message": if (arg === undefined) return true; if (repeated) return this.messages(arg, field.T(), allowExcessProperties, depth); return this.message(arg, field.T(), allowExcessProperties, depth); case "map": if (typeof arg != 'object' || arg === null) return false; if (depth < 2) return true; if (!this.mapKeys(arg, field.K, depth)) return false; switch (field.V.kind) { case "scalar": return this.scalars(Object.values(arg), field.V.T, depth, field.V.L); case "enum": return this.scalars(Object.values(arg), ScalarType.INT32, depth); case "message": return this.messages(Object.values(arg), field.V.T(), allowExcessProperties, depth); } break; } return true; } message(arg, type, allowExcessProperties, depth) { if (allowExcessProperties) { return type.isAssignable(arg, depth); } return type.is(arg, depth); } messages(arg, type, allowExcessProperties, depth) { if (!Array.isArray(arg)) return false; if (depth < 2) return true; if (allowExcessProperties) { for (let i = 0; i < arg.length && i < depth; i++) if (!type.isAssignable(arg[i], depth - 1)) return false; } else { for (let i = 0; i < arg.length && i < depth; i++) if (!type.is(arg[i], depth - 1)) return false; } return true; } scalar(arg, type, longType) { let argType = typeof arg; switch (type) { case ScalarType.UINT64: case ScalarType.FIXED64: case ScalarType.INT64: case ScalarType.SFIXED64: case ScalarType.SINT64: switch (longType) { case LongType.BIGINT: return argType == "bigint"; case LongType.NUMBER: return argType == "number" && !isNaN(arg); default: return argType == "string"; } case ScalarType.BOOL: return argType == 'boolean'; case ScalarType.STRING: return argType == 'string'; case ScalarType.BYTES: return arg instanceof Uint8Array; case ScalarType.DOUBLE: case ScalarType.FLOAT: return argType == 'number' && !isNaN(arg); default: // case ScalarType.UINT32: // case ScalarType.FIXED32: // case ScalarType.INT32: // case ScalarType.SINT32: // case ScalarType.SFIXED32: return argType == 'number' && Number.isInteger(arg); } } scalars(arg, type, depth, longType) { if (!Array.isArray(arg)) return false; if (depth < 2) return true; if (Array.isArray(arg)) for (let i = 0; i < arg.length && i < depth; i++) if (!this.scalar(arg[i], type, longType)) return false; return true; } mapKeys(map, type, depth) { let keys = Object.keys(map); switch (type) { case ScalarType.INT32: case ScalarType.FIXED32: case ScalarType.SFIXED32: case ScalarType.SINT32: case ScalarType.UINT32: return this.scalars(keys.slice(0, depth).map(k => parseInt(k)), type, depth); case ScalarType.BOOL: return this.scalars(keys.slice(0, depth).map(k => k == 'true' ? true : k == 'false' ? false : k), type, depth); default: return this.scalars(keys, type, depth, LongType.STRING); } } } /** * Utility method to convert a PbLong or PbUlong to a JavaScript * representation during runtime. * * Works with generated field information, `undefined` is equivalent * to `STRING`. */ function reflectionLongConvert(long, type) { switch (type) { case LongType.BIGINT: return long.toBigInt(); case LongType.NUMBER: return long.toNumber(); default: // case undefined: // case LongType.STRING: return long.toString(); } } /** * Reads proto3 messages in canonical JSON format using reflection information. * * https://developers.google.com/protocol-buffers/docs/proto3#json */ class ReflectionJsonReader { constructor(info) { this.info = info; } prepare() { var _a; if (this.fMap === undefined) { this.fMap = {}; const fieldsInput = (_a = this.info.fields) !== null && _a !== void 0 ? _a : []; for (const field of fieldsInput) { this.fMap[field.name] = field; this.fMap[field.jsonName] = field; this.fMap[field.localName] = field; } } } // Cannot parse JSON for #. assert(condition, fieldName, jsonValue) { if (!condition) { let what = typeofJsonValue(jsonValue); if (what == "number" || what == "boolean") what = jsonValue.toString(); throw new Error(`Cannot parse JSON ${what} for ${this.info.typeName}#${fieldName}`); } } /** * Reads a message from canonical JSON format into the target message. * * Repeated fields are appended. Map entries are added, overwriting * existing keys. * * If a message field is already present, it will be merged with the * new data. */ read(input, message, options) { this.prepare(); const oneofsHandled = []; for (const [jsonKey, jsonValue] of Object.entries(input)) { const field = this.fMap[jsonKey]; if (!field) { if (!options.ignoreUnknownFields) throw new Error(`Found unknown field while reading ${this.info.typeName} from JSON format. JSON key: ${jsonKey}`); continue; } const localName = field.localName; // handle oneof ADT let target; // this will be the target for the field value, whether it is member of a oneof or not if (field.oneof) { if (jsonValue === null && (field.kind !== 'enum' || field.T()[0] !== 'google.protobuf.NullValue')) { continue; } // since json objects are unordered by specification, it is not possible to take the last of multiple oneofs if (oneofsHandled.includes(field.oneof)) throw new Error(`Multiple members of the oneof group "${field.oneof}" of ${this.info.typeName} are present in JSON.`); oneofsHandled.push(field.oneof); target = message[field.oneof] = { oneofKind: localName }; } else { target = message; } // we have handled oneof above. we just have read the value into `target`. if (field.kind == 'map') { if (jsonValue === null) { continue; } // check input this.assert(isJsonObject(jsonValue), field.name, jsonValue); // our target to put map entries into const fieldObj = target[localName]; // read entries for (const [jsonObjKey, jsonObjValue] of Object.entries(jsonValue)) { this.assert(jsonObjValue !== null, field.name + " map value", null); // read value let val; switch (field.V.kind) { case "message": val = field.V.T().internalJsonRead(jsonObjValue, options); break; case "enum": val = this.enum(field.V.T(), jsonObjValue, field.name, options.ignoreUnknownFields); if (val === false) continue; break; case "scalar": val = this.scalar(jsonObjValue, field.V.T, field.V.L, field.name); break; } this.assert(val !== undefined, field.name + " map value", jsonObjValue); // read key let key = jsonObjKey; if (field.K == ScalarType.BOOL) key = key == "true" ? true : key == "false" ? false : key; key = this.scalar(key, field.K, LongType.STRING, field.name).toString(); fieldObj[key] = val; } } else if (field.repeat) { if (jsonValue === null) continue; // check input this.assert(Array.isArray(jsonValue), field.name, jsonValue); // our target to put array entries into const fieldArr = target[localName]; // read array entries for (const jsonItem of jsonValue) { this.assert(jsonItem !== null, field.name, null); let val; switch (field.kind) { case "message": val = field.T().internalJsonRead(jsonItem, options); break; case "enum": val = this.enum(field.T(), jsonItem, field.name, options.ignoreUnknownFields); if (val === false) continue; break; case "scalar": val = this.scalar(jsonItem, field.T, field.L, field.name); break; } this.assert(val !== undefined, field.name, jsonValue); fieldArr.push(val); } } else { switch (field.kind) { case "message": if (jsonValue === null && field.T().typeName != 'google.protobuf.Value') { this.assert(field.oneof === undefined, field.name + " (oneof member)", null); continue; } target[localName] = field.T().internalJsonRead(jsonValue, options, target[localName]); break; case "enum": if (jsonValue === null) continue; let val = this.enum(field.T(), jsonValue, field.name, options.ignoreUnknownFields); if (val === false) continue; target[localName] = val; break; case "scalar": if (jsonValue === null) continue; target[localName] = this.scalar(jsonValue, field.T, field.L, field.name); break; } } } } /** * Returns `false` for unrecognized string representations. * * google.protobuf.NullValue accepts only JSON `null` (or the old `"NULL_VALUE"`). */ enum(type, json, fieldName, ignoreUnknownFields) { if (type[0] == 'google.protobuf.NullValue') assert(json === null || json === "NULL_VALUE", `Unable to parse field ${this.info.typeName}#${fieldName}, enum ${type[0]} only accepts null.`); if (json === null) // we require 0 to be default value for all enums return 0; switch (typeof json) { case "number": assert(Number.isInteger(json), `Unable to parse field ${this.info.typeName}#${fieldName}, enum can only be integral number, got ${json}.`); return json; case "string": let localEnumName = json; if (type[2] && json.substring(0, type[2].length) === type[2]) // lookup without the shared prefix localEnumName = json.substring(type[2].length); let enumNumber = type[1][localEnumName]; if (typeof enumNumber === 'undefined' && ignoreUnknownFields) { return false; } assert(typeof enumNumber == "number", `Unable to parse field ${this.info.typeName}#${fieldName}, enum ${type[0]} has no value for "${json}".`); return enumNumber; } assert(false, `Unable to parse field ${this.info.typeName}#${fieldName}, cannot parse enum value from ${typeof json}".`); } scalar(json, type, longType, fieldName) { let e; try { switch (type) { // float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity". // Either numbers or strings are accepted. Exponent notation is also accepted. case ScalarType.DOUBLE: case ScalarType.FLOAT: if (json === null) return .0; if (json === "NaN") return Number.NaN; if (json === "Infinity") return Number.POSITIVE_INFINITY; if (json === "-Infinity") return Number.NEGATIVE_INFINITY; if (json === "") { e = "empty string"; break; } if (typeof json == "string" && json.trim().length !== json.length) { e = "extra whitespace"; break; } if (typeof json != "string" && typeof json != "number") { break; } let float = Number(json); if (Number.isNaN(float)) { e = "not a number"; break; } if (!Number.isFinite(float)) { // infinity and -infinity are handled by string representation above, so this is an error e = "too large or small"; break; } if (type == ScalarType.FLOAT) assertFloat32(float); return float; // int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted. case ScalarType.INT32: case ScalarType.FIXED32: case ScalarType.SFIXED32: case ScalarType.SINT32: case ScalarType.UINT32: if (json === null) return 0; let int32; if (typeof json == "number") int32 = json; else if (json === "") e = "empty string"; else if (typeof json == "string") { if (json.trim().length !== json.length) e = "extra whitespace"; else int32 = Number(json); } if (int32 === undefined) break; if (type == ScalarType.UINT32) assertUInt32(int32); else assertInt32(int32); return int32; // int64, fixed64, uint64: JSON value will be a decimal string. Either numbers or strings are accepted. case ScalarType.INT64: case ScalarType.SFIXED64: case ScalarType.SINT64: if (json === null) return reflectionLongConvert(PbLong.ZERO, longType); if (typeof json != "number" && typeof json != "string") break; return reflectionLongConvert(PbLong.from(json), longType); case ScalarType.FIXED64: case ScalarType.UINT64: if (json === null) return reflectionLongConvert(PbULong.ZERO, longType); if (typeof json != "number" && typeof json != "string") break; return reflectionLongConvert(PbULong.from(json), longType); // bool: case ScalarType.BOOL: if (json === null) return false; if (typeof json !== "boolean") break; return json; // string: case ScalarType.STRING: if (json === null) return ""; if (typeof json !== "string") { e = "extra whitespace"; break; } try { encodeURIComponent(json); } catch (e) { e = "invalid UTF8"; break; } return json; // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings. // Either standard or URL-safe base64 encoding with/without paddings are accepted. case ScalarType.BYTES: if (json === null || json === "") return new Uint8Array(0); if (typeof json !== 'string') break; return base64decode(json); } } catch (error) { e = error.message; } this.assert(false, fieldName + (e ? " - " + e : ""), json); } } /** * Writes proto3 messages in canonical JSON format using reflection * information. * * https://developers.google.com/protocol-buffers/docs/proto3#json */ class ReflectionJsonWriter { constructor(info) { var _a; this.fields = (_a = info.fields) !== null && _a !== void 0 ? _a : []; } /** * Converts the message to a JSON object, based on the field descriptors. */ write(message, options) { const json = {}, source = message; for (const field of this.fields) { // field is not part of a oneof, simply write as is if (!field.oneof) { let jsonValue = this.field(field, source[field.localName], options); if (jsonValue !== undefined) json[options.useProtoFieldName ? field.name : field.jsonName] = jsonValue; continue; } // field is part of a oneof const group = source[field.oneof]; if (group.oneofKind !== field.localName) continue; // not selected, skip const opt = field.kind == 'scalar' || field.kind == 'enum' ? Object.assign(Object.assign({}, options), { emitDefaultValues: true }) : options; let jsonValue = this.field(field, group[field.localName], opt); assert(jsonValue !== undefined); json[options.useProtoFieldName ? field.name : field.jsonName] = jsonValue; } return json; } field(field, value, options) { let jsonValue = undefined; if (field.kind == 'map') { assert(typeof value == "object" && value !== null); const jsonObj = {}; switch (field.V.kind) { case "scalar": for (const [entryKey, entryValue] of Object.entries(value)) { const val = this.scalar(field.V.T, entryValue, field.name, false, true); assert(val !== undefined); jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key } break; case "message": const messageType = field.V.T(); for (const [entryKey, entryValue] of Object.entries(value)) { const val = this.message(messageType, entryValue, field.name, options); assert(val !== undefined); jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key } break; case "enum": const enumInfo = field.V.T(); for (const [entryKey, entryValue] of Object.entries(value)) { assert(entryValue === undefined || typeof entryValue == 'number'); const val = this.enum(enumInfo, entryValue, field.name, false, true, options.enumAsInteger); assert(val !== undefined); jsonObj[entryKey.toString()] = val; // JSON standard allows only (double quoted) string as property key } break; } if (options.emitDefaultValues || Object.keys(jsonObj).length > 0) jsonValue = jsonObj; } else if (field.repeat) { assert(Array.isArray(value)); const jsonArr = []; switch (field.kind) { case "scalar": for (let i = 0; i < value.length; i++) { const val = this.scalar(field.T, value[i], field.name, field.opt, true); assert(val !== undefined); jsonArr.push(val); } break; case "enum": const enumInfo = field.T(); for (let i = 0; i < value.length; i++) { assert(value[i] === undefined || typeof value[i] == 'number'); const val = this.enum(enumInfo, value[i], field.name, field.opt, true, options.enumAsInteger); assert(val !== undefined); jsonArr.push(val); } break; case "message": const messageType = field.T(); for (let i = 0; i < value.length; i++) { const val = this.message(messageType, value[i], field.name, options); assert(val !== undefined); jsonArr.push(val); } break; } // add converted array to json output if (options.emitDefaultValues || jsonArr.length > 0 || options.emitDefaultValues) jsonValue = jsonArr; } else { switch (field.kind) { case "scalar": jsonValue = this.scalar(field.T, value, field.name, field.opt, options.emitDefaultValues); break; case "enum": jsonValue = this.enum(field.T(), value, field.name, field.opt, options.emitDefaultValues, options.enumAsInteger); break; case "message": jsonValue = this.message(field.T(), value, field.name, options); break; } } return jsonValue; } /** * Returns `null` as the default for google.protobuf.NullValue. */ enum(type, value, fieldName, optional, emitDefaultValues, enumAsInteger) { if (type[0] == 'google.protobuf.NullValue') return !emitDefaultValues && !optional ? undefined : null; if (value === undefined) { assert(optional); return undefined; } if (value === 0 && !emitDefaultValues && !optional) // we require 0 to be default value for all enums return undefined; assert(typeof value == 'number'); assert(Number.isInteger(value)); if (enumAsInteger || !type[1].hasOwnProperty(value)) // if we don't now the enum value, just return the number return value; if (type[2]) // restore the dropped prefix return type[2] + type[1][value]; return type[1][value]; } message(type, value, fieldName, options) { if (value === undefined) return options.emitDefaultValues ? null : undefined; return type.internalJsonWrite(value, options); } scalar(type, value, fieldName, optional, emitDefaultValues) { if (value === undefined) { assert(optional); return undefined; } const ed = emitDefaultValues || optional; // noinspection FallThroughInSwitchStatementJS switch (type) { // int32, fixed32, uint32: JSON value will be a decimal number. Either numbers or strings are accepted. case ScalarType.INT32: case ScalarType.SFIXED32: case ScalarType.SINT32: if (value === 0) return ed ? 0 : undefined; assertInt32(value); return value; case ScalarType.FIXED32: case ScalarType.UINT32: if (value === 0) return ed ? 0 : undefined; assertUInt32(value); return value; // float, double: JSON value will be a number or one of the special string values "NaN", "Infinity", and "-Infinity". // Either numbers or strings are accepted. Exponent notation is also accepted. case ScalarType.FLOAT: assertFloat32(value); case ScalarType.DOUBLE: if (value === 0) return ed ? 0 : undefined; assert(typeof value == 'number'); if (Number.isNaN(value)) return 'NaN'; if (value === Number.POSITIVE_INFINITY) return 'Infinity'; if (value === Number.NEGATIVE_INFINITY) return '-Infinity'; return value; // string: case ScalarType.STRING: if (value === "") return ed ? '' : undefined; assert(typeof value == 'string'); return value; // bool: case ScalarType.BOOL: if (value === false) return ed ? false : undefined; assert(typeof value == 'boolean'); return value; // JSON value will be a decimal string. Either numbers or strings are accepted. case ScalarType.UINT64: case ScalarType.FIXED64: assert(typeof value == 'number' || typeof value == 'string' || typeof value == 'bigint'); let ulong = PbULong.from(value); if (ulong.isZero() && !ed) return undefined; return ulong.toString(); // JSON value will be a decimal string. Either numbers or strings are accepted. case ScalarType.INT64: case ScalarType.SFIXED64: case ScalarType.SINT64: assert(typeof value == 'number' || typeof value == 'string' || typeof value == 'bigint'); let long = PbLong.from(value); if (long.isZero() && !ed) return undefined; return long.toString(); // bytes: JSON value will be the data encoded as a string using standard base64 encoding with paddings. // Either standard or URL-safe base64 encoding with/without paddings are accepted. case ScalarType.BYTES: assert(value instanceof Uint8Array); if (!value.byteLength) return ed ? "" : undefined; return base64encode(value); } } } /** * Creates the default value for a scalar type. */ function reflectionScalarDefault(type, longType = LongType.STRING) { switch (type) { case ScalarType.BOOL: return false; case ScalarType.UINT64: case ScalarType.FIXED64: return reflectionLongConvert(PbULong.ZERO, longType); case ScalarType.INT64: case ScalarType.SFIXED64: case ScalarType.SINT64: return reflectionLongConvert(PbLong.ZERO, longType); case ScalarType.DOUBLE: case ScalarType.FLOAT: return 0.0; case ScalarType.BYTES: return new Uint8Array(0); case ScalarType.STRING: return ""; default: // case ScalarType.INT32: // case ScalarType.UINT32: // case ScalarType.SINT32: // case ScalarType.FIXED32: // case ScalarType.SFIXED32: return 0; } } /** * Reads proto3 messages in binary format using reflection information. * * https://developers.google.com/protocol-buffers/docs/encoding */ class ReflectionBinaryReader { constructor(info) { this.info = info; } prepare() { var _a; if (!this.fieldNoToField) { const fieldsInput = (_a = this.info.fields) !== null && _a !== void 0 ? _a : []; this.fieldNoToField = new Map(fieldsInput.map(field => [field.no, field])); } } /** * Reads a message from binary format into the target message. * * Repeated fields are appended. Map entries are added, overwriting * existing keys. * * If a message field is already present, it will be merged with the * new data. */ read(reader, message, options, length) { this.prepare(); const end = length === undefined ? reader.len : reader.pos + length; while (reader.pos < end) { // read the tag and find the field const [fieldNo, wireType] = reader.tag(), field = this.fieldNoToField.get(fieldNo); if (!field) { let u = options.readUnknownField; if (u == "throw") throw new Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.info.typeName}`); let d = reader.skip(wireType); if (u !== false) (u === true ? UnknownFieldHandler.onRead : u)(this.info.typeName, message, fieldNo, wireType, d); continue; } // target object for the field we are reading let target = message, repeated = field.repeat, localName = field.localName; // if field is member of oneof ADT, use ADT as target if (field.oneof) { target = target[field.oneof]; // if other oneof member selected, set new ADT if (target.oneofKind !== localName) target = message[field.oneof] = { oneofKind: localName }; } // we have handled oneof above, we just have read the value into `target[localName]` switch (field.kind) { case "scalar": case "enum": let T = field.kind == "enum" ? ScalarType.INT32 : field.T; let L = field.kind == "scalar" ? field.L : undefined; if (repeated) { let arr = target[localName]; // safe to assume presence of array, oneof cannot contain repeated values if (wireType == WireType.LengthDelimited && T != ScalarType.STRING && T != ScalarType.BYTES) { let e = reader.uint32() + reader.pos; while (reader.pos < e) arr.push(this.scalar(reader, T, L)); } else arr.push(this.scalar(reader, T, L)); } else target[localName] = this.scalar(reader, T, L); break; case "message": if (repeated) { let arr = target[localName]; // safe to assume presence of array, oneof cannot contain repeated values let msg = field.T().internalBinaryRead(reader, reader.uint32(), options); arr.push(msg); } else target[localName] = field.T().internalBinaryRead(reader, reader.uint32(), options, target[localName]); break; case "map": let [mapKey, mapVal] = this.mapEntry(field, reader, options); // safe to assume presence of map object, oneof cannot contain repeated values target[localName][mapKey] = mapVal; break; } } } /** * Read a map field, expecting key field = 1, value field = 2 */ mapEntry(field, reader, options) { let length = reader.uint32(); let end = reader.pos + length; let key = undefined; // javascript only allows number or string for object properties let val = undefined; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { case 1: if (field.K == ScalarType.BOOL) key = reader.bool().toString(); else // long types are read as string, number types are okay as number key = this.scalar(reader, field.K, LongType.STRING); break; case 2: switch (field.V.kind) { case "scalar": val = this.scalar(reader, field.V.T, field.V.L); break; case "enum": val = reader.int32(); break; case "message": val = field.V.T().internalBinaryRead(reader, reader.uint32(), options); break; } break; default: throw new Error(`Unknown field ${fieldNo} (wire type ${wireType}) in map entry for ${this.info.typeName}#${field.name}`); } } if (key === undefined) { let keyRaw = reflectionScalarDefault(field.K); key = field.K == ScalarType.BOOL ? keyRaw.toString() : keyRaw; } if (val === undefined) switch (field.V.kind) { case "scalar": val = reflectionScalarDefault(field.V.T, field.V.L); break; case "enum": val = 0; break; case "message": val = field.V.T().create(); break; } return [key, val]; } scalar(reader, type, longType) { switch (type) { case ScalarType.INT32: return reader.int32(); case ScalarType.STRING: return reader.string(); case ScalarType.BOOL: return reader.bool(); case ScalarType.DOUBLE: return reader.double(); case ScalarType.FLOAT: return reader.float(); case ScalarType.INT64: return reflectionLongConvert(reader.int64(), longType); case ScalarType.UINT64: return reflectionLongConvert(reader.uint64(), longType); case ScalarType.FIXED64: return reflectionLongConvert(reader.fixed64(), longType); case ScalarType.FIXED32: return reader.fixed32(); case ScalarType.BYTES: return reader.bytes(); case ScalarType.UINT32: return reader.uint32(); case ScalarType.SFIXED32: return reader.sfixed32(); case ScalarType.SFIXED64: return reflectionLongConvert(reader.sfixed64(), longType); case ScalarType.SINT32: return reader.sint32(); case ScalarType.SINT64: return reflectionLongConvert(reader.sint64(), longType); } } } /** * Writes proto3 messages in binary format using reflection information. * * https://developers.google.com/protocol-buffers/docs/encoding */ class ReflectionBinaryWriter { constructor(info) { this.info = info; } prepare() { if (!this.fields) { const fieldsInput = this.info.fields ? this.info.fields.concat() : []; this.fields = fieldsInput.sort((a, b) => a.no - b.no); } } /** * Writes the message to binary format. */ write(message, writer, options) { this.prepare(); for (const field of this.fields) { let value, // this will be our field value, whether it is member of a oneof or not emitDefault, // whether we emit the default value (only true for oneof members) repeated = field.repeat, localName = field.localName; // handle oneof ADT if (field.oneof) { const group = message[field.oneof]; if (group.oneofKind !== localName) continue; // if field is not selected, skip value = group[localName]; emitDefault = true; } else { value = message[localName]; emitDefault = false; } // we have handled oneof above. we just have to honor `emitDefault`. switch (field.kind) { case "scalar": case "enum": let T = field.kind == "enum" ? ScalarType.INT32 : field.T; if (repeated) { assert(Array.isArray(value)); if (repeated == RepeatType.PACKED) this.packed(writer, T, field.no, value); else for (const item of value) this.scalar(writer, T, field.no, item, true); } else if (value === undefined) assert(field.opt); else this.scalar(writer, T, field.no, value, emitDefault || field.opt); break; case "message": if (repeated) { assert(Array.isArray(value)); for (const item of value) this.message(writer, options, field.T(), field.no, item); } else { this.message(writer, options, field.T(), field.no, value); } break; case "map": assert(typeof value == 'object' && value !== null); for (const [key, val] of Object.entries(value)) this.mapEntry(writer, options, field, key, val); break; } } let u = options.writeUnknownFields; if (u !== false) (u === true ? UnknownFieldHandler.onWrite : u)(this.info.typeName, message, writer); } mapEntry(writer, options, field, key, value) { writer.tag(field.no, WireType.LengthDelimited); writer.fork(); // javascript only allows number or string for object properties // we convert from our representation to the protobuf type let keyValue = key; switch (field.K) { case ScalarType.INT32: case ScalarType.FIXED32: case ScalarType.UINT32: case ScalarType.SFIXED32: case ScalarType.SINT32: keyValue = Number.parseInt(key); break; case ScalarType.BOOL: assert(key == 'true' || key == 'false'); keyValue = key == 'true'; break; } // write key, expecting key field number = 1 this.scalar(writer, field.K, 1, keyValue, true); // write value, expecting value field number = 2 switch (field.V.kind) { case 'scalar': this.scalar(writer, field.V.T, 2, value, true); break; case 'enum': this.scalar(writer, ScalarType.INT32, 2, value, true); break; case 'message': this.message(writer, options, field.V.T(), 2, value); break; } writer.join(); } message(writer, options, handler, fieldNo, value) { if (value === undefined) return; handler.internalBinaryWrite(value, writer.tag(fieldNo, WireType.LengthDelimited).fork(), options); writer.join(); } /** * Write a single scalar value. */ scalar(writer, type, fieldNo, value, emitDefault) { let [wireType, method, isDefault] = this.scalarInfo(type, value); if (!isDefault || emitDefault) { writer.tag(fieldNo, wireType); writer[method](value); } } /** * Write an array of scalar values in packed format. */ packed(writer, type, fieldNo, value) { if (!value.length) return; assert(type !== ScalarType.BYTES && type !== ScalarType.STRING); // write tag writer.tag(fieldNo, WireType.LengthDelimited); // begin length-delimited writer.fork(); // write values without tags let [, method,] = this.scalarInfo(type); for (let i = 0; i < value.length; i++) writer[method](value[i]); // end length delimited writer.join(); } /** * Get information for writing a scalar value. * * Returns tuple: * [0]: appropriate WireType * [1]: name of the appropriate method of IBinaryWriter * [2]: whether the given value is a default value * * If argument `value` is omitted, [2] is always false. */ scalarInfo(type, value) { let t = WireType.Varint; let m; let i = value === undefined; let d = value === 0; switch (type) { case ScalarType.INT32: m = "int32"; break; case ScalarType.STRING: d = i || !value.length; t = WireType.LengthDelimited; m = "string"; break; case ScalarType.BOOL: d = value === false; m = "bool"; break; case ScalarType.UINT32: m = "uint32"; break; case ScalarType.DOUBLE: t = WireType.Bit64; m = "double"; break; case ScalarType.FLOAT: t = WireType.Bit32; m = "float"; break; case ScalarType.INT64: d = i || PbLong.from(value).isZero(); m = "int64"; break; case ScalarType.UINT64: d = i || PbULong.from(value).isZero(); m = "uint64"; break; case ScalarType.FIXED64: d = i || PbULong.from(value).isZero(); t = WireType.Bit64; m = "fixed64"; break; case ScalarType.BYTES: d = i || !value.byteLength; t = WireType.LengthDelimited; m = "bytes"; break; case ScalarType.FIXED32: t = WireType.Bit32; m = "fixed32"; break; case ScalarType.SFIXED32: t = WireType.Bit32; m = "sfixed32"; break; case ScalarType.SFIXED64: d = i || PbLong.from(value).isZero(); t = WireType.Bit64; m = "sfixed64"; break; case ScalarType.SINT32: m = "sint32"; break; case ScalarType.SINT64: d = i || PbLong.from(value).isZero(); m = "sint64"; break; } return [t, m, i || d]; } } /** * Creates an instance of the generic message, using the field * information. */ function reflectionCreate(type) { /** * This ternary can be removed in the next major version. * The `Object.create()` code path utilizes a new `messagePrototype` * property on the `IMessageType` which has this same `MESSAGE_TYPE` * non-enumerable property on it. Doing it this way means that we only * pay the cost of `Object.defineProperty()` once per `IMessageType` * class of once per "instance". The falsy code path is only provided * for backwards compatibility in cases where the runtime library is * updated without also updating the generated code. */ const msg = type.messagePrototype ? Object.create(type.messagePrototype) : Object.defineProperty({}, MESSAGE_TYPE, { value: type }); for (let field of type.fields) { let name = field.localName; if (field.opt) continue; if (field.oneof) msg[field.oneof] = { oneofKind: undefined }; else if (field.repeat) msg[name] = []; else switch (field.kind) { case "scalar": msg[name] = reflectionScalarDefault(field.T, field.L); break; case "enum": // we require 0 to be default value for all enums msg[name] = 0; break; case "map": msg[name] = {}; break; } } return msg; } /** * Copy partial data into the target message. * * If a singular scalar or enum field is present in the source, it * replaces the field in the target. * * If a singular message field is present in the source, it is merged * with the target field by calling mergePartial() of the responsible * message type. * * If a repeated field is present in the source, its values replace * all values in the target array, removing extraneous values. * Repeated message fields are copied, not merged. * * If a map field is present in the source, entries are added to the * target map, replacing entries with the same key. Entries that only * exist in the target remain. Entries with message values are copied, * not merged. * * Note that this function differs from protobuf merge semantics, * which appends repeated fields. */ function reflectionMergePartial(info, target, source) { let fieldValue, // the field value we are working with input = source, output; // where we want our field value to go for (let field of info.fields) { let name = field.localName; if (field.oneof) { const group = input[field.oneof]; // this is the oneof`s group in the source if ((group === null || group === void 0 ? void 0 : group.oneofKind) == undefined) { // the user is free to omit continue; // we skip this field, and all other members too } fieldValue = group[name]; // our value comes from the the oneof group of the source output = target[field.oneof]; // and our output is the oneof group of the target output.oneofKind = group.oneofKind; // always update discriminator if (fieldValue == undefined) { delete output[name]; // remove any existing value continue; // skip further work on field } } else { fieldValue = input[name]; // we are using the source directly output = target; // we want our field value to go directly into the target if (fieldValue == undefined) { continue; // skip further work on field, existing value is used as is } } if (field.repeat) output[name].length = fieldValue.length; // resize target array to match source array // now we just work with `fieldValue` and `output` to merge the value switch (field.kind) { case "scalar": case "enum": if (field.repeat) for (let i = 0; i < fieldValue.length; i++) output[name][i] = fieldValue[i]; // not a reference type else output[name] = fieldValue; // not a reference type break; case "message": let T = field.T(); if (field.repeat) for (let i = 0; i < fieldValue.length; i++) output[name][i] = T.create(fieldValue[i]); else if (output[name] === undefined) output[name] = T.create(fieldValue); // nothing to merge with else T.mergePartial(output[name], fieldValue); break; case "map": // Map and repeated fields are simply overwritten, not appended or merged switch (field.V.kind) { case "scalar": case "enum": Object.assign(output[name], fieldValue); // elements are not reference types break; case "message": let T = field.V.T(); for (let k of Object.keys(fieldValue)) output[name][k] = T.create(fieldValue[k]); break; } break; } } } /** * Determines whether two message of the same type have the same field values. * Checks for deep equality, traversing repeated fields, oneof groups, maps * and messages recursively. * Will also return true if both messages are `undefined`. */ function reflectionEquals(info, a, b) { if (a === b) return true; if (!a || !b) return false; for (let field of info.fields) { let localName = field.localName; let val_a = field.oneof ? a[field.oneof][localName] : a[localName]; let val_b = field.oneof ? b[field.oneof][localName] : b[localName]; switch (field.kind) { case "enum": case "scalar": let t = field.kind == "enum" ? ScalarType.INT32 : field.T; if (!(field.repeat ? repeatedPrimitiveEq(t, val_a, val_b) : primitiveEq(t, val_a, val_b))) return false; break; case "map": if (!(field.V.kind == "message" ? repeatedMsgEq(field.V.T(), objectValues(val_a), objectValues(val_b)) : repeatedPrimitiveEq(field.V.kind == "enum" ? ScalarType.INT32 : field.V.T, objectValues(val_a), objectValues(val_b)))) return false; break; case "message": let T = field.T(); if (!(field.repeat ? repeatedMsgEq(T, val_a, val_b) : T.equals(val_a, val_b))) return false; break; } } return true; } const objectValues = Object.values; function primitiveEq(type, a, b) { if (a === b) return true; if (type !== ScalarType.BYTES) return false; let ba = a; let bb = b; if (ba.length !== bb.length) return false; for (let i = 0; i < ba.length; i++) if (ba[i] != bb[i]) return false; return true; } function repeatedPrimitiveEq(type, a, b) { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) if (!primitiveEq(type, a[i], b[i])) return false; return true; } function repeatedMsgEq(type, a, b) { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) if (!type.equals(a[i], b[i])) return false; return true; } const baseDescriptors = Object.getOwnPropertyDescriptors(Object.getPrototypeOf({})); const messageTypeDescriptor = baseDescriptors[MESSAGE_TYPE] = {}; /** * This standard message type provides reflection-based * operations to work with a message. */ class MessageType { constructor(name, fields, options) { this.defaultCheckDepth = 16; this.typeName = name; this.fields = fields.map(normalizeFieldInfo); this.options = options !== null && options !== void 0 ? options : {}; messageTypeDescriptor.value = this; this.messagePrototype = Object.create(null, baseDescriptors); this.refTypeCheck = new ReflectionTypeCheck(this); this.refJsonReader = new ReflectionJsonReader(this); this.refJsonWriter = new ReflectionJsonWriter(this); this.refBinReader = new ReflectionBinaryReader(this); this.refBinWriter = new ReflectionBinaryWriter(this); } create(value) { let message = reflectionCreate(this); if (value !== undefined) { reflectionMergePartial(this, message, value); } return message; } /** * Clone the message. * * Unknown fields are discarded. */ clone(message) { let copy = this.create(); reflectionMergePartial(this, copy, message); return copy; } /** * Determines whether two message of the same type have the same field values. * Checks for deep equality, traversing repeated fields, oneof groups, maps * and messages recursively. * Will also return true if both messages are `undefined`. */ equals(a, b) { return reflectionEquals(this, a, b); } /** * Is the given value assignable to our message type * and contains no [excess properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks)? */ is(arg, depth = this.defaultCheckDepth) { return this.refTypeCheck.is(arg, depth, false); } /** * Is the given value assignable to our message type, * regardless of [excess properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks)? */ isAssignable(arg, depth = this.defaultCheckDepth) { return this.refTypeCheck.is(arg, depth, true); } /** * Copy partial data into the target message. */ mergePartial(target, source) { reflectionMergePartial(this, target, source); } /** * Create a new message from binary format. */ fromBinary(data, options) { let opt = binaryReadOptions(options); return this.internalBinaryRead(opt.readerFactory(data), data.byteLength, opt); } /** * Read a new message from a JSON value. */ fromJson(json, options) { return this.internalJsonRead(json, jsonReadOptions(options)); } /** * Read a new message from a JSON string. * This is equivalent to `T.fromJson(JSON.parse(json))`. */ fromJsonString(json, options) { let value = JSON.parse(json); return this.fromJson(value, options); } /** * Write the message to canonical JSON value. */ toJson(message, options) { return this.internalJsonWrite(message, jsonWriteOptions(options)); } /** * Convert the message to canonical JSON string. * This is equivalent to `JSON.stringify(T.toJson(t))` */ toJsonString(message, options) { var _a; let value = this.toJson(message, options); return JSON.stringify(value, null, (_a = options === null || options === void 0 ? void 0 : options.prettySpaces) !== null && _a !== void 0 ? _a : 0); } /** * Write the message to binary format. */ toBinary(message, options) { let opt = binaryWriteOptions(options); return this.internalBinaryWrite(message, opt.writerFactory(), opt).finish(); } /** * This is an internal method. If you just want to read a message from * JSON, use `fromJson()` or `fromJsonString()`. * * Reads JSON value and merges the fields into the target * according to protobuf rules. If the target is omitted, * a new instance is created first. */ internalJsonRead(json, options, target) { if (json !== null && typeof json == "object" && !Array.isArray(json)) { let message = target !== null && target !== void 0 ? target : this.create(); this.refJsonReader.read(json, message, options); return message; } throw new Error(`Unable to parse message ${this.typeName} from JSON ${typeofJsonValue(json)}.`); } /** * This is an internal method. If you just want to write a message * to JSON, use `toJson()` or `toJsonString(). * * Writes JSON value and returns it. */ internalJsonWrite(message, options) { return this.refJsonWriter.write(message, options); } /** * This is an internal method. If you just want to write a message * in binary format, use `toBinary()`. * * Serializes the message in binary format and appends it to the given * writer. Returns passed writer. */ internalBinaryWrite(message, writer, options) { this.refBinWriter.write(message, writer, options); return writer; } /** * This is an internal method. If you just want to read a message from * binary data, use `fromBinary()`. * * Reads data from binary format and merges the fields into * the target according to protobuf rules. If the target is * omitted, a new instance is created first. */ internalBinaryRead(reader, length, options, target) { let message = target !== null && target !== void 0 ? target : this.create(); this.refBinReader.read(reader, message, options, length); return message; } } /** * Turns PartialMethodInfo into MethodInfo. */ function normalizeMethodInfo(method, service) { var _a, _b, _c; let m = method; m.service = service; m.localName = (_a = m.localName) !== null && _a !== void 0 ? _a : lowerCamelCase(m.name); // noinspection PointlessBooleanExpressionJS m.serverStreaming = !!m.serverStreaming; // noinspection PointlessBooleanExpressionJS m.clientStreaming = !!m.clientStreaming; m.options = (_b = m.options) !== null && _b !== void 0 ? _b : {}; m.idempotency = (_c = m.idempotency) !== null && _c !== void 0 ? _c : undefined; return m; } class ServiceType { constructor(typeName, methods, options) { this.typeName = typeName; this.methods = methods.map(i => normalizeMethodInfo(i, this)); this.options = options !== null && options !== void 0 ? options : {}; } } // @generated message type with reflection information, may provide speed optimized methods class CacheScope$Type extends MessageType { constructor() { super("github.actions.results.entities.v1.CacheScope", [ { no: 1, name: "scope", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, { no: 2, name: "permission", kind: "scalar", T: 3 /*ScalarType.INT64*/ } ]); } create(value) { const message = { scope: "", permission: "0" }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); return message; } internalBinaryRead(reader, length, options, target) { let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { case /* string scope */ 1: message.scope = reader.string(); break; case /* int64 permission */ 2: message.permission = reader.int64().toString(); break; default: let u = options.readUnknownField; if (u === "throw") throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); let d = reader.skip(wireType); if (u !== false) (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); } } return message; } internalBinaryWrite(message, writer, options) { /* string scope = 1; */ if (message.scope !== "") writer.tag(1, WireType.LengthDelimited).string(message.scope); /* int64 permission = 2; */ if (message.permission !== "0") writer.tag(2, WireType.Varint).int64(message.permission); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); return writer; } } /** * @generated MessageType for protobuf message github.actions.results.entities.v1.CacheScope */ const CacheScope = new CacheScope$Type(); // @generated message type with reflection information, may provide speed optimized methods class CacheMetadata$Type extends MessageType { constructor() { super("github.actions.results.entities.v1.CacheMetadata", [ { no: 1, name: "repository_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ }, { no: 2, name: "scope", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => CacheScope } ]); } create(value) { const message = { repositoryId: "0", scope: [] }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); return message; } internalBinaryRead(reader, length, options, target) { let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { case /* int64 repository_id */ 1: message.repositoryId = reader.int64().toString(); break; case /* repeated github.actions.results.entities.v1.CacheScope scope */ 2: message.scope.push(CacheScope.internalBinaryRead(reader, reader.uint32(), options)); break; default: let u = options.readUnknownField; if (u === "throw") throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); let d = reader.skip(wireType); if (u !== false) (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); } } return message; } internalBinaryWrite(message, writer, options) { /* int64 repository_id = 1; */ if (message.repositoryId !== "0") writer.tag(1, WireType.Varint).int64(message.repositoryId); /* repeated github.actions.results.entities.v1.CacheScope scope = 2; */ for (let i = 0; i < message.scope.length; i++) CacheScope.internalBinaryWrite(message.scope[i], writer.tag(2, WireType.LengthDelimited).fork(), options).join(); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); return writer; } } /** * @generated MessageType for protobuf message github.actions.results.entities.v1.CacheMetadata */ const CacheMetadata = new CacheMetadata$Type(); // @generated by protobuf-ts 2.9.1 with parameter long_type_string,client_none,generate_dependencies // @generated from protobuf file "results/api/v1/cache.proto" (package "github.actions.results.api.v1", syntax proto3) // tslint:disable // @generated message type with reflection information, may provide speed optimized methods class CreateCacheEntryRequest$Type extends MessageType { constructor() { super("github.actions.results.api.v1.CreateCacheEntryRequest", [ { no: 1, name: "metadata", kind: "message", T: () => CacheMetadata }, { no: 2, name: "key", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, { no: 3, name: "version", kind: "scalar", T: 9 /*ScalarType.STRING*/ } ]); } create(value) { const message = { key: "", version: "" }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); return message; } internalBinaryRead(reader, length, options, target) { let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { case /* github.actions.results.entities.v1.CacheMetadata metadata */ 1: message.metadata = CacheMetadata.internalBinaryRead(reader, reader.uint32(), options, message.metadata); break; case /* string key */ 2: message.key = reader.string(); break; case /* string version */ 3: message.version = reader.string(); break; default: let u = options.readUnknownField; if (u === "throw") throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); let d = reader.skip(wireType); if (u !== false) (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); } } return message; } internalBinaryWrite(message, writer, options) { /* github.actions.results.entities.v1.CacheMetadata metadata = 1; */ if (message.metadata) CacheMetadata.internalBinaryWrite(message.metadata, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); /* string key = 2; */ if (message.key !== "") writer.tag(2, WireType.LengthDelimited).string(message.key); /* string version = 3; */ if (message.version !== "") writer.tag(3, WireType.LengthDelimited).string(message.version); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); return writer; } } /** * @generated MessageType for protobuf message github.actions.results.api.v1.CreateCacheEntryRequest */ const CreateCacheEntryRequest = new CreateCacheEntryRequest$Type(); // @generated message type with reflection information, may provide speed optimized methods class CreateCacheEntryResponse$Type extends MessageType { constructor() { super("github.actions.results.api.v1.CreateCacheEntryResponse", [ { no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, { no: 2, name: "signed_upload_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, { no: 3, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ } ]); } create(value) { const message = { ok: false, signedUploadUrl: "", message: "" }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); return message; } internalBinaryRead(reader, length, options, target) { let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { case /* bool ok */ 1: message.ok = reader.bool(); break; case /* string signed_upload_url */ 2: message.signedUploadUrl = reader.string(); break; case /* string message */ 3: message.message = reader.string(); break; default: let u = options.readUnknownField; if (u === "throw") throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); let d = reader.skip(wireType); if (u !== false) (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); } } return message; } internalBinaryWrite(message, writer, options) { /* bool ok = 1; */ if (message.ok !== false) writer.tag(1, WireType.Varint).bool(message.ok); /* string signed_upload_url = 2; */ if (message.signedUploadUrl !== "") writer.tag(2, WireType.LengthDelimited).string(message.signedUploadUrl); /* string message = 3; */ if (message.message !== "") writer.tag(3, WireType.LengthDelimited).string(message.message); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); return writer; } } /** * @generated MessageType for protobuf message github.actions.results.api.v1.CreateCacheEntryResponse */ const CreateCacheEntryResponse = new CreateCacheEntryResponse$Type(); // @generated message type with reflection information, may provide speed optimized methods class FinalizeCacheEntryUploadRequest$Type extends MessageType { constructor() { super("github.actions.results.api.v1.FinalizeCacheEntryUploadRequest", [ { no: 1, name: "metadata", kind: "message", T: () => CacheMetadata }, { no: 2, name: "key", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, { no: 3, name: "size_bytes", kind: "scalar", T: 3 /*ScalarType.INT64*/ }, { no: 4, name: "version", kind: "scalar", T: 9 /*ScalarType.STRING*/ } ]); } create(value) { const message = { key: "", sizeBytes: "0", version: "" }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); return message; } internalBinaryRead(reader, length, options, target) { let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { case /* github.actions.results.entities.v1.CacheMetadata metadata */ 1: message.metadata = CacheMetadata.internalBinaryRead(reader, reader.uint32(), options, message.metadata); break; case /* string key */ 2: message.key = reader.string(); break; case /* int64 size_bytes */ 3: message.sizeBytes = reader.int64().toString(); break; case /* string version */ 4: message.version = reader.string(); break; default: let u = options.readUnknownField; if (u === "throw") throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); let d = reader.skip(wireType); if (u !== false) (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); } } return message; } internalBinaryWrite(message, writer, options) { /* github.actions.results.entities.v1.CacheMetadata metadata = 1; */ if (message.metadata) CacheMetadata.internalBinaryWrite(message.metadata, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); /* string key = 2; */ if (message.key !== "") writer.tag(2, WireType.LengthDelimited).string(message.key); /* int64 size_bytes = 3; */ if (message.sizeBytes !== "0") writer.tag(3, WireType.Varint).int64(message.sizeBytes); /* string version = 4; */ if (message.version !== "") writer.tag(4, WireType.LengthDelimited).string(message.version); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); return writer; } } /** * @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeCacheEntryUploadRequest */ const FinalizeCacheEntryUploadRequest = new FinalizeCacheEntryUploadRequest$Type(); // @generated message type with reflection information, may provide speed optimized methods class FinalizeCacheEntryUploadResponse$Type extends MessageType { constructor() { super("github.actions.results.api.v1.FinalizeCacheEntryUploadResponse", [ { no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, { no: 2, name: "entry_id", kind: "scalar", T: 3 /*ScalarType.INT64*/ }, { no: 3, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ } ]); } create(value) { const message = { ok: false, entryId: "0", message: "" }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); return message; } internalBinaryRead(reader, length, options, target) { let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { case /* bool ok */ 1: message.ok = reader.bool(); break; case /* int64 entry_id */ 2: message.entryId = reader.int64().toString(); break; case /* string message */ 3: message.message = reader.string(); break; default: let u = options.readUnknownField; if (u === "throw") throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); let d = reader.skip(wireType); if (u !== false) (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); } } return message; } internalBinaryWrite(message, writer, options) { /* bool ok = 1; */ if (message.ok !== false) writer.tag(1, WireType.Varint).bool(message.ok); /* int64 entry_id = 2; */ if (message.entryId !== "0") writer.tag(2, WireType.Varint).int64(message.entryId); /* string message = 3; */ if (message.message !== "") writer.tag(3, WireType.LengthDelimited).string(message.message); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); return writer; } } /** * @generated MessageType for protobuf message github.actions.results.api.v1.FinalizeCacheEntryUploadResponse */ const FinalizeCacheEntryUploadResponse = new FinalizeCacheEntryUploadResponse$Type(); // @generated message type with reflection information, may provide speed optimized methods class GetCacheEntryDownloadURLRequest$Type extends MessageType { constructor() { super("github.actions.results.api.v1.GetCacheEntryDownloadURLRequest", [ { no: 1, name: "metadata", kind: "message", T: () => CacheMetadata }, { no: 2, name: "key", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, { no: 3, name: "restore_keys", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, { no: 4, name: "version", kind: "scalar", T: 9 /*ScalarType.STRING*/ } ]); } create(value) { const message = { key: "", restoreKeys: [], version: "" }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); return message; } internalBinaryRead(reader, length, options, target) { let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { case /* github.actions.results.entities.v1.CacheMetadata metadata */ 1: message.metadata = CacheMetadata.internalBinaryRead(reader, reader.uint32(), options, message.metadata); break; case /* string key */ 2: message.key = reader.string(); break; case /* repeated string restore_keys */ 3: message.restoreKeys.push(reader.string()); break; case /* string version */ 4: message.version = reader.string(); break; default: let u = options.readUnknownField; if (u === "throw") throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); let d = reader.skip(wireType); if (u !== false) (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); } } return message; } internalBinaryWrite(message, writer, options) { /* github.actions.results.entities.v1.CacheMetadata metadata = 1; */ if (message.metadata) CacheMetadata.internalBinaryWrite(message.metadata, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); /* string key = 2; */ if (message.key !== "") writer.tag(2, WireType.LengthDelimited).string(message.key); /* repeated string restore_keys = 3; */ for (let i = 0; i < message.restoreKeys.length; i++) writer.tag(3, WireType.LengthDelimited).string(message.restoreKeys[i]); /* string version = 4; */ if (message.version !== "") writer.tag(4, WireType.LengthDelimited).string(message.version); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); return writer; } } /** * @generated MessageType for protobuf message github.actions.results.api.v1.GetCacheEntryDownloadURLRequest */ const GetCacheEntryDownloadURLRequest = new GetCacheEntryDownloadURLRequest$Type(); // @generated message type with reflection information, may provide speed optimized methods class GetCacheEntryDownloadURLResponse$Type extends MessageType { constructor() { super("github.actions.results.api.v1.GetCacheEntryDownloadURLResponse", [ { no: 1, name: "ok", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, { no: 2, name: "signed_download_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, { no: 3, name: "matched_key", kind: "scalar", T: 9 /*ScalarType.STRING*/ } ]); } create(value) { const message = { ok: false, signedDownloadUrl: "", matchedKey: "" }; globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); if (value !== undefined) reflectionMergePartial(this, message, value); return message; } internalBinaryRead(reader, length, options, target) { let message = target !== null && target !== void 0 ? target : this.create(), end = reader.pos + length; while (reader.pos < end) { let [fieldNo, wireType] = reader.tag(); switch (fieldNo) { case /* bool ok */ 1: message.ok = reader.bool(); break; case /* string signed_download_url */ 2: message.signedDownloadUrl = reader.string(); break; case /* string matched_key */ 3: message.matchedKey = reader.string(); break; default: let u = options.readUnknownField; if (u === "throw") throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); let d = reader.skip(wireType); if (u !== false) (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); } } return message; } internalBinaryWrite(message, writer, options) { /* bool ok = 1; */ if (message.ok !== false) writer.tag(1, WireType.Varint).bool(message.ok); /* string signed_download_url = 2; */ if (message.signedDownloadUrl !== "") writer.tag(2, WireType.LengthDelimited).string(message.signedDownloadUrl); /* string matched_key = 3; */ if (message.matchedKey !== "") writer.tag(3, WireType.LengthDelimited).string(message.matchedKey); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); return writer; } } /** * @generated MessageType for protobuf message github.actions.results.api.v1.GetCacheEntryDownloadURLResponse */ const GetCacheEntryDownloadURLResponse = new GetCacheEntryDownloadURLResponse$Type(); /** * @generated ServiceType for protobuf service github.actions.results.api.v1.CacheService */ new ServiceType("github.actions.results.api.v1.CacheService", [ { name: "CreateCacheEntry", options: {}, I: CreateCacheEntryRequest, O: CreateCacheEntryResponse }, { name: "FinalizeCacheEntryUpload", options: {}, I: FinalizeCacheEntryUploadRequest, O: FinalizeCacheEntryUploadResponse }, { name: "GetCacheEntryDownloadURL", options: {}, I: GetCacheEntryDownloadURLRequest, O: GetCacheEntryDownloadURLResponse } ]); class CacheServiceClientJSON { constructor(rpc) { this.rpc = rpc; this.CreateCacheEntry.bind(this); this.FinalizeCacheEntryUpload.bind(this); this.GetCacheEntryDownloadURL.bind(this); } CreateCacheEntry(request) { const data = CreateCacheEntryRequest.toJson(request, { useProtoFieldName: true, emitDefaultValues: false, }); const promise = this.rpc.request("github.actions.results.api.v1.CacheService", "CreateCacheEntry", "application/json", data); return promise.then((data) => CreateCacheEntryResponse.fromJson(data, { ignoreUnknownFields: true, })); } FinalizeCacheEntryUpload(request) { const data = FinalizeCacheEntryUploadRequest.toJson(request, { useProtoFieldName: true, emitDefaultValues: false, }); const promise = this.rpc.request("github.actions.results.api.v1.CacheService", "FinalizeCacheEntryUpload", "application/json", data); return promise.then((data) => FinalizeCacheEntryUploadResponse.fromJson(data, { ignoreUnknownFields: true, })); } GetCacheEntryDownloadURL(request) { const data = GetCacheEntryDownloadURLRequest.toJson(request, { useProtoFieldName: true, emitDefaultValues: false, }); const promise = this.rpc.request("github.actions.results.api.v1.CacheService", "GetCacheEntryDownloadURL", "application/json", data); return promise.then((data) => GetCacheEntryDownloadURLResponse.fromJson(data, { ignoreUnknownFields: true, })); } } /** * Masks the `sig` parameter in a URL and sets it as a secret. * * @param url - The URL containing the signature parameter to mask * @remarks * This function attempts to parse the provided URL and identify the 'sig' query parameter. * If found, it registers both the raw and URL-encoded signature values as secrets using * the Actions `setSecret` API, which prevents them from being displayed in logs. * * The function handles errors gracefully if URL parsing fails, logging them as debug messages. * * @example * ```typescript * // Mask a signature in an Azure SAS token URL * maskSigUrl('https://example.blob.core.windows.net/container/file.txt?sig=abc123&se=2023-01-01'); * ``` */ function maskSigUrl(url) { if (!url) return; try { const parsedUrl = new URL(url); const signature = parsedUrl.searchParams.get('sig'); if (signature) { setSecret(signature); setSecret(encodeURIComponent(signature)); } } catch (error) { debug(`Failed to parse URL: ${url} ${error instanceof Error ? error.message : String(error)}`); } } /** * Masks sensitive information in URLs containing signature parameters. * Currently supports masking 'sig' parameters in the 'signed_upload_url' * and 'signed_download_url' properties of the provided object. * * @param body - The object should contain a signature * @remarks * This function extracts URLs from the object properties and calls maskSigUrl * on each one to redact sensitive signature information. The function doesn't * modify the original object; it only marks the signatures as secrets for * logging purposes. * * @example * ```typescript * const responseBody = { * signed_upload_url: 'https://blob.core.windows.net/?sig=abc123', * signed_download_url: 'https://blob.core/windows.net/?sig=def456' * }; * maskSecretUrls(responseBody); * ``` */ function maskSecretUrls(body) { if (typeof body !== 'object' || body === null) { debug('body is not an object or is null'); return; } if ('signed_upload_url' in body && typeof body.signed_upload_url === 'string') { maskSigUrl(body.signed_upload_url); } if ('signed_download_url' in body && typeof body.signed_download_url === 'string') { maskSigUrl(body.signed_download_url); } } var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * This class is a wrapper around the CacheServiceClientJSON class generated by Twirp. * * It adds retry logic to the request method, which is not present in the generated client. * * This class is used to interact with cache service v2. */ class CacheServiceClient { constructor(userAgent, maxAttempts, baseRetryIntervalMilliseconds, retryMultiplier) { this.maxAttempts = 5; this.baseRetryIntervalMilliseconds = 3000; this.retryMultiplier = 1.5; const token = getRuntimeToken(); this.baseUrl = getCacheServiceURL(); if (maxAttempts) { this.maxAttempts = maxAttempts; } if (baseRetryIntervalMilliseconds) { this.baseRetryIntervalMilliseconds = baseRetryIntervalMilliseconds; } if (retryMultiplier) { this.retryMultiplier = retryMultiplier; } this.httpClient = new HttpClient(userAgent, [ new BearerCredentialHandler(token) ]); } // This function satisfies the Rpc interface. It is compatible with the JSON // JSON generated client. request(service, method, contentType, data) { return __awaiter$2(this, void 0, void 0, function* () { const url = new URL(`/twirp/${service}/${method}`, this.baseUrl).href; debug(`[Request] ${method} ${url}`); const headers = { 'Content-Type': contentType }; try { const { body } = yield this.retryableRequest(() => __awaiter$2(this, void 0, void 0, function* () { return this.httpClient.post(url, JSON.stringify(data), headers); })); return body; } catch (error) { throw new Error(`Failed to ${method}: ${error.message}`); } }); } retryableRequest(operation) { return __awaiter$2(this, void 0, void 0, function* () { let attempt = 0; let errorMessage = ''; let rawBody = ''; while (attempt < this.maxAttempts) { let isRetryable = false; try { const response = yield operation(); const statusCode = response.message.statusCode; rawBody = yield response.readBody(); debug(`[Response] - ${response.message.statusCode}`); debug(`Headers: ${JSON.stringify(response.message.headers, null, 2)}`); const body = JSON.parse(rawBody); maskSecretUrls(body); debug(`Body: ${JSON.stringify(body, null, 2)}`); if (this.isSuccessStatusCode(statusCode)) { return { response, body }; } isRetryable = this.isRetryableHttpStatusCode(statusCode); errorMessage = `Failed request: (${statusCode}) ${response.message.statusMessage}`; if (body.msg) { if (UsageError.isUsageErrorMessage(body.msg)) { throw new UsageError(); } errorMessage = `${errorMessage}: ${body.msg}`; } // Handle rate limiting - don't retry, just warn and exit // For more info, see https://docs.github.com/en/actions/reference/limits if (statusCode === HttpCodes.TooManyRequests) { const retryAfterHeader = response.message.headers['retry-after']; if (retryAfterHeader) { const parsedSeconds = parseInt(retryAfterHeader, 10); if (!isNaN(parsedSeconds) && parsedSeconds > 0) { warning(`You've hit a rate limit, your rate limit will reset in ${parsedSeconds} seconds`); } } throw new RateLimitError(`Rate limited: ${errorMessage}`); } } catch (error) { if (error instanceof SyntaxError) { debug(`Raw Body: ${rawBody}`); } if (error instanceof UsageError) { throw error; } if (error instanceof RateLimitError) { throw error; } if (NetworkError.isNetworkErrorCode(error === null || error === void 0 ? void 0 : error.code)) { throw new NetworkError(error === null || error === void 0 ? void 0 : error.code); } isRetryable = true; errorMessage = error.message; } if (!isRetryable) { throw new Error(`Received non-retryable error: ${errorMessage}`); } if (attempt + 1 === this.maxAttempts) { throw new Error(`Failed to make request after ${this.maxAttempts} attempts: ${errorMessage}`); } const retryTimeMilliseconds = this.getExponentialRetryTimeMilliseconds(attempt); info(`Attempt ${attempt + 1} of ${this.maxAttempts} failed with error: ${errorMessage}. Retrying request in ${retryTimeMilliseconds} ms...`); yield this.sleep(retryTimeMilliseconds); attempt++; } throw new Error(`Request failed`); }); } isSuccessStatusCode(statusCode) { if (!statusCode) return false; return statusCode >= 200 && statusCode < 300; } isRetryableHttpStatusCode(statusCode) { if (!statusCode) return false; const retryableStatusCodes = [ HttpCodes.BadGateway, HttpCodes.GatewayTimeout, HttpCodes.InternalServerError, HttpCodes.ServiceUnavailable ]; return retryableStatusCodes.includes(statusCode); } sleep(milliseconds) { return __awaiter$2(this, void 0, void 0, function* () { return new Promise(resolve => setTimeout(resolve, milliseconds)); }); } getExponentialRetryTimeMilliseconds(attempt) { if (attempt < 0) { throw new Error('attempt should be a positive integer'); } if (attempt === 0) { return this.baseRetryIntervalMilliseconds; } const minTime = this.baseRetryIntervalMilliseconds * Math.pow(this.retryMultiplier, attempt); const maxTime = minTime * this.retryMultiplier; // returns a random number between minTime and maxTime (exclusive) return Math.trunc(Math.random() * (maxTime - minTime) + minTime); } } function internalCacheTwirpClient(options) { const client = new CacheServiceClient(getUserAgentString(), void 0 , void 0 , void 0 ); return new CacheServiceClientJSON(client); } var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; const IS_WINDOWS = process.platform === 'win32'; // Returns tar path and type: BSD or GNU function getTarPath() { return __awaiter$1(this, void 0, void 0, function* () { switch (process.platform) { case 'win32': { const gnuTar = yield getGnuTarPathOnWindows(); const systemTar = SystemTarPathOnWindows; if (gnuTar) { // Use GNUtar as default on windows return { path: gnuTar, type: ArchiveToolType.GNU }; } else if (existsSync(systemTar)) { return { path: systemTar, type: ArchiveToolType.BSD }; } break; } case 'darwin': { const gnuTar = yield which('gtar', false); if (gnuTar) { // fix permission denied errors when extracting BSD tar archive with GNU tar - https://github.com/actions/cache/issues/527 return { path: gnuTar, type: ArchiveToolType.GNU }; } else { return { path: yield which('tar', true), type: ArchiveToolType.BSD }; } } } // Default assumption is GNU tar is present in path return { path: yield which('tar', true), type: ArchiveToolType.GNU }; }); } // Return arguments for tar as per tarPath, compressionMethod, method type and os function getTarArgs(tarPath_1, compressionMethod_1, type_1) { return __awaiter$1(this, arguments, void 0, function* (tarPath, compressionMethod, type, archivePath = '') { const args = [`"${tarPath.path}"`]; const cacheFileName = getCacheFileName(compressionMethod); const tarFile = 'cache.tar'; const workingDirectory = getWorkingDirectory(); // Speficic args for BSD tar on windows for workaround const BSD_TAR_ZSTD = tarPath.type === ArchiveToolType.BSD && compressionMethod !== CompressionMethod.Gzip && IS_WINDOWS; // Method specific args switch (type) { case 'create': args.push('--posix', '-cf', BSD_TAR_ZSTD ? tarFile : cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '--exclude', BSD_TAR_ZSTD ? tarFile : cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '-P', '-C', workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '--files-from', ManifestFilename); break; case 'extract': args.push('-xf', BSD_TAR_ZSTD ? tarFile : archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '-P', '-C', workingDirectory.replace(new RegExp(`\\${path.sep}`, 'g'), '/')); break; case 'list': args.push('-tf', BSD_TAR_ZSTD ? tarFile : archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), '-P'); break; } // Platform specific args if (tarPath.type === ArchiveToolType.GNU) { switch (process.platform) { case 'win32': args.push('--force-local'); break; case 'darwin': args.push('--delay-directory-restore'); break; } } return args; }); } // Returns commands to run tar and compression program function getCommands(compressionMethod_1, type_1) { return __awaiter$1(this, arguments, void 0, function* (compressionMethod, type, archivePath = '') { let args; const tarPath = yield getTarPath(); const tarArgs = yield getTarArgs(tarPath, compressionMethod, type, archivePath); const compressionArgs = type !== 'create' ? yield getDecompressionProgram(tarPath, compressionMethod, archivePath) : yield getCompressionProgram(tarPath, compressionMethod); const BSD_TAR_ZSTD = tarPath.type === ArchiveToolType.BSD && compressionMethod !== CompressionMethod.Gzip && IS_WINDOWS; if (BSD_TAR_ZSTD && type !== 'create') { args = [[...compressionArgs].join(' '), [...tarArgs].join(' ')]; } else { args = [[...tarArgs].join(' '), [...compressionArgs].join(' ')]; } if (BSD_TAR_ZSTD) { return args; } return [args.join(' ')]; }); } function getWorkingDirectory() { var _a; return (_a = process.env['GITHUB_WORKSPACE']) !== null && _a !== void 0 ? _a : process.cwd(); } // Common function for extractTar and listTar to get the compression method function getDecompressionProgram(tarPath, compressionMethod, archivePath) { return __awaiter$1(this, void 0, void 0, function* () { // -d: Decompress. // unzstd is equivalent to 'zstd -d' // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. // Using 30 here because we also support 32-bit self-hosted runners. const BSD_TAR_ZSTD = tarPath.type === ArchiveToolType.BSD && compressionMethod !== CompressionMethod.Gzip && IS_WINDOWS; switch (compressionMethod) { case CompressionMethod.Zstd: return BSD_TAR_ZSTD ? [ 'zstd -d --long=30 --force -o', TarFilename, archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/') ] : [ '--use-compress-program', IS_WINDOWS ? '"zstd -d --long=30"' : 'unzstd --long=30' ]; case CompressionMethod.ZstdWithoutLong: return BSD_TAR_ZSTD ? [ 'zstd -d --force -o', TarFilename, archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/') ] : ['--use-compress-program', IS_WINDOWS ? '"zstd -d"' : 'unzstd']; default: return ['-z']; } }); } // Used for creating the archive // -T#: Compress using # working thread. If # is 0, attempt to detect and use the number of physical CPU cores. // zstdmt is equivalent to 'zstd -T0' // --long=#: Enables long distance matching with # bits. Maximum is 30 (1GB) on 32-bit OS and 31 (2GB) on 64-bit. // Using 30 here because we also support 32-bit self-hosted runners. // Long range mode is added to zstd in v1.3.2 release, so we will not use --long in older version of zstd. function getCompressionProgram(tarPath, compressionMethod) { return __awaiter$1(this, void 0, void 0, function* () { const cacheFileName = getCacheFileName(compressionMethod); const BSD_TAR_ZSTD = tarPath.type === ArchiveToolType.BSD && compressionMethod !== CompressionMethod.Gzip && IS_WINDOWS; switch (compressionMethod) { case CompressionMethod.Zstd: return BSD_TAR_ZSTD ? [ 'zstd -T0 --long=30 --force -o', cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), TarFilename ] : [ '--use-compress-program', IS_WINDOWS ? '"zstd -T0 --long=30"' : 'zstdmt --long=30' ]; case CompressionMethod.ZstdWithoutLong: return BSD_TAR_ZSTD ? [ 'zstd -T0 --force -o', cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'), TarFilename ] : ['--use-compress-program', IS_WINDOWS ? '"zstd -T0"' : 'zstdmt']; default: return ['-z']; } }); } // Executes all commands as separate processes function execCommands(commands, cwd) { return __awaiter$1(this, void 0, void 0, function* () { for (const command of commands) { try { yield exec(command, undefined, { cwd, env: Object.assign(Object.assign({}, process.env), { MSYS: 'winsymlinks:nativestrict' }) }); } catch (error) { throw new Error(`${command.split(' ')[0]} failed with error: ${error === null || error === void 0 ? void 0 : error.message}`); } } }); } // List the contents of a tar function listTar(archivePath, compressionMethod) { return __awaiter$1(this, void 0, void 0, function* () { const commands = yield getCommands(compressionMethod, 'list', archivePath); yield execCommands(commands); }); } // Extract a tar function extractTar(archivePath, compressionMethod) { return __awaiter$1(this, void 0, void 0, function* () { // Create directory to extract tar into const workingDirectory = getWorkingDirectory(); yield mkdirP(workingDirectory); const commands = yield getCommands(compressionMethod, 'extract', archivePath); yield execCommands(commands); }); } // Create a tar function createTar(archiveFolder, sourceDirectories, compressionMethod) { return __awaiter$1(this, void 0, void 0, function* () { // Write source directories to manifest.txt to avoid command length limits writeFileSync(path.join(archiveFolder, ManifestFilename), sourceDirectories.join('\n')); const commands = yield getCommands(compressionMethod, 'create'); yield execCommands(commands, archiveFolder); }); } var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; class ValidationError extends Error { constructor(message) { super(message); this.name = 'ValidationError'; Object.setPrototypeOf(this, ValidationError.prototype); } } class ReserveCacheError extends Error { constructor(message) { super(message); this.name = 'ReserveCacheError'; Object.setPrototypeOf(this, ReserveCacheError.prototype); } } class FinalizeCacheError extends Error { constructor(message) { super(message); this.name = 'FinalizeCacheError'; Object.setPrototypeOf(this, FinalizeCacheError.prototype); } } function checkPaths(paths) { if (!paths || paths.length === 0) { throw new ValidationError(`Path Validation Error: At least one directory or file path is required`); } } function checkKey(key) { if (key.length > 512) { throw new ValidationError(`Key Validation Error: ${key} cannot be larger than 512 characters.`); } const regex = /^[^,]*$/; if (!regex.test(key)) { throw new ValidationError(`Key Validation Error: ${key} cannot contain commas.`); } } /** * isFeatureAvailable to check the presence of Actions cache service * * @returns boolean return true if Actions cache service feature is available, otherwise false */ function isFeatureAvailable() { const cacheServiceVersion = getCacheServiceVersion(); // Check availability based on cache service version switch (cacheServiceVersion) { case 'v2': // For v2, we need ACTIONS_RESULTS_URL return !!process.env['ACTIONS_RESULTS_URL']; case 'v1': default: // For v1, we only need ACTIONS_CACHE_URL return !!process.env['ACTIONS_CACHE_URL']; } } /** * Restores cache from keys * * @param paths a list of file paths to restore from the cache * @param primaryKey an explicit key for restoring the cache. Lookup is done with prefix matching. * @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for primaryKey * @param downloadOptions cache download options * @param enableCrossOsArchive an optional boolean enabled to restore on windows any cache created on any platform * @returns string returns the key for the cache hit, otherwise returns undefined */ function restoreCache(paths_1, primaryKey_1, restoreKeys_1, options_1) { return __awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) { const cacheServiceVersion = getCacheServiceVersion(); debug(`Cache service version: ${cacheServiceVersion}`); checkPaths(paths); switch (cacheServiceVersion) { case 'v2': return yield restoreCacheV2(paths, primaryKey, restoreKeys, options, enableCrossOsArchive); case 'v1': default: return yield restoreCacheV1(paths, primaryKey, restoreKeys, options, enableCrossOsArchive); } }); } /** * Restores cache using the legacy Cache Service * * @param paths a list of file paths to restore from the cache * @param primaryKey an explicit key for restoring the cache. Lookup is done with prefix matching. * @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for primaryKey * @param options cache download options * @param enableCrossOsArchive an optional boolean enabled to restore on Windows any cache created on any platform * @returns string returns the key for the cache hit, otherwise returns undefined */ function restoreCacheV1(paths_1, primaryKey_1, restoreKeys_1, options_1) { return __awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) { restoreKeys = restoreKeys || []; const keys = [primaryKey, ...restoreKeys]; debug('Resolved Keys:'); debug(JSON.stringify(keys)); if (keys.length > 10) { throw new ValidationError(`Key Validation Error: Keys are limited to a maximum of 10.`); } for (const key of keys) { checkKey(key); } const compressionMethod = yield getCompressionMethod(); let archivePath = ''; try { // path are needed to compute version const cacheEntry = yield getCacheEntry(keys, paths, { compressionMethod, enableCrossOsArchive }); if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) { // Cache not found return undefined; } if (options === null || options === void 0 ? void 0 : options.lookupOnly) { info('Lookup only - skipping download'); return cacheEntry.cacheKey; } archivePath = path.join(yield createTempDirectory(), getCacheFileName(compressionMethod)); debug(`Archive Path: ${archivePath}`); // Download the cache from the cache entry yield downloadCache(cacheEntry.archiveLocation, archivePath, options); if (isDebug()) { yield listTar(archivePath, compressionMethod); } const archiveFileSize = getArchiveFileSizeInBytes(archivePath); info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`); yield extractTar(archivePath, compressionMethod); info('Cache restored successfully'); return cacheEntry.cacheKey; } catch (error$1) { const typedError = error$1; if (typedError.name === ValidationError.name) { throw error$1; } else { // warn on cache restore failure and continue build // Log server errors (5xx) as errors, all other errors as warnings if (typedError instanceof HttpClientError && typeof typedError.statusCode === 'number' && typedError.statusCode >= 500) { error(`Failed to restore: ${error$1.message}`); } else { warning(`Failed to restore: ${error$1.message}`); } } } finally { // Try to delete the archive to save space try { yield unlinkFile(archivePath); } catch (error) { debug(`Failed to delete archive: ${error}`); } } return undefined; }); } /** * Restores cache using Cache Service v2 * * @param paths a list of file paths to restore from the cache * @param primaryKey an explicit key for restoring the cache. Lookup is done with prefix matching * @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for primaryKey * @param downloadOptions cache download options * @param enableCrossOsArchive an optional boolean enabled to restore on windows any cache created on any platform * @returns string returns the key for the cache hit, otherwise returns undefined */ function restoreCacheV2(paths_1, primaryKey_1, restoreKeys_1, options_1) { return __awaiter(this, arguments, void 0, function* (paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) { // Override UploadOptions to force the use of Azure options = Object.assign(Object.assign({}, options), { useAzureSdk: true }); restoreKeys = restoreKeys || []; const keys = [primaryKey, ...restoreKeys]; debug('Resolved Keys:'); debug(JSON.stringify(keys)); if (keys.length > 10) { throw new ValidationError(`Key Validation Error: Keys are limited to a maximum of 10.`); } for (const key of keys) { checkKey(key); } let archivePath = ''; try { const twirpClient = internalCacheTwirpClient(); const compressionMethod = yield getCompressionMethod(); const request = { key: primaryKey, restoreKeys, version: getCacheVersion(paths, compressionMethod, enableCrossOsArchive) }; const response = yield twirpClient.GetCacheEntryDownloadURL(request); if (!response.ok) { debug(`Cache not found for version ${request.version} of keys: ${keys.join(', ')}`); return undefined; } const isRestoreKeyMatch = request.key !== response.matchedKey; if (isRestoreKeyMatch) { info(`Cache hit for restore-key: ${response.matchedKey}`); } else { info(`Cache hit for: ${response.matchedKey}`); } if (options === null || options === void 0 ? void 0 : options.lookupOnly) { info('Lookup only - skipping download'); return response.matchedKey; } archivePath = path.join(yield createTempDirectory(), getCacheFileName(compressionMethod)); debug(`Archive path: ${archivePath}`); debug(`Starting download of archive to: ${archivePath}`); yield downloadCache(response.signedDownloadUrl, archivePath, options); const archiveFileSize = getArchiveFileSizeInBytes(archivePath); info(`Cache Size: ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B)`); if (isDebug()) { yield listTar(archivePath, compressionMethod); } yield extractTar(archivePath, compressionMethod); info('Cache restored successfully'); return response.matchedKey; } catch (error$1) { const typedError = error$1; if (typedError.name === ValidationError.name) { throw error$1; } else { // Supress all non-validation cache related errors because caching should be optional // Log server errors (5xx) as errors, all other errors as warnings if (typedError instanceof HttpClientError && typeof typedError.statusCode === 'number' && typedError.statusCode >= 500) { error(`Failed to restore: ${error$1.message}`); } else { warning(`Failed to restore: ${error$1.message}`); } } } finally { try { if (archivePath) { yield unlinkFile(archivePath); } } catch (error) { debug(`Failed to delete archive: ${error}`); } } return undefined; }); } /** * Saves a list of files with the specified key * * @param paths a list of file paths to be cached * @param key an explicit key for restoring the cache * @param enableCrossOsArchive an optional boolean enabled to save cache on windows which could be restored on any platform * @param options cache upload options * @returns number returns cacheId if the cache was saved successfully and throws an error if save fails */ function saveCache(paths_1, key_1, options_1) { return __awaiter(this, arguments, void 0, function* (paths, key, options, enableCrossOsArchive = false) { const cacheServiceVersion = getCacheServiceVersion(); debug(`Cache service version: ${cacheServiceVersion}`); checkPaths(paths); checkKey(key); switch (cacheServiceVersion) { case 'v2': return yield saveCacheV2(paths, key, options, enableCrossOsArchive); case 'v1': default: return yield saveCacheV1(paths, key, options, enableCrossOsArchive); } }); } /** * Save cache using the legacy Cache Service * * @param paths * @param key * @param options * @param enableCrossOsArchive * @returns */ function saveCacheV1(paths_1, key_1, options_1) { return __awaiter(this, arguments, void 0, function* (paths, key, options, enableCrossOsArchive = false) { var _a, _b, _c, _d, _e; const compressionMethod = yield getCompressionMethod(); let cacheId = -1; const cachePaths = yield resolvePaths(paths); debug('Cache Paths:'); debug(`${JSON.stringify(cachePaths)}`); if (cachePaths.length === 0) { throw new Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`); } const archiveFolder = yield createTempDirectory(); const archivePath = path.join(archiveFolder, getCacheFileName(compressionMethod)); debug(`Archive Path: ${archivePath}`); try { yield createTar(archiveFolder, cachePaths, compressionMethod); if (isDebug()) { yield listTar(archivePath, compressionMethod); } const fileSizeLimit = 10 * 1024 * 1024 * 1024; // 10GB per repo limit const archiveFileSize = getArchiveFileSizeInBytes(archivePath); debug(`File Size: ${archiveFileSize}`); // For GHES, this check will take place in ReserveCache API with enterprise file size limit if (archiveFileSize > fileSizeLimit && !isGhes()) { throw new Error(`Cache size of ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B) is over the 10GB limit, not saving cache.`); } debug('Reserving Cache'); const reserveCacheResponse = yield reserveCache(key, paths, { compressionMethod, enableCrossOsArchive, cacheSize: archiveFileSize }); if ((_a = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _a === void 0 ? void 0 : _a.cacheId) { cacheId = (_b = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _b === void 0 ? void 0 : _b.cacheId; } else if ((reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.statusCode) === 400) { throw new Error((_d = (_c = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.error) === null || _c === void 0 ? void 0 : _c.message) !== null && _d !== void 0 ? _d : `Cache size of ~${Math.round(archiveFileSize / (1024 * 1024))} MB (${archiveFileSize} B) is over the data cap limit, not saving cache.`); } else { throw new ReserveCacheError(`Unable to reserve cache with key ${key}, another job may be creating this cache. More details: ${(_e = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.error) === null || _e === void 0 ? void 0 : _e.message}`); } debug(`Saving Cache (ID: ${cacheId})`); yield saveCache$1(cacheId, archivePath, '', options); } catch (error$1) { const typedError = error$1; if (typedError.name === ValidationError.name) { throw error$1; } else if (typedError.name === ReserveCacheError.name) { info(`Failed to save: ${typedError.message}`); } else { // Log server errors (5xx) as errors, all other errors as warnings if (typedError instanceof HttpClientError && typeof typedError.statusCode === 'number' && typedError.statusCode >= 500) { error(`Failed to save: ${typedError.message}`); } else { warning(`Failed to save: ${typedError.message}`); } } } finally { // Try to delete the archive to save space try { yield unlinkFile(archivePath); } catch (error) { debug(`Failed to delete archive: ${error}`); } } return cacheId; }); } /** * Save cache using Cache Service v2 * * @param paths a list of file paths to restore from the cache * @param key an explicit key for restoring the cache * @param options cache upload options * @param enableCrossOsArchive an optional boolean enabled to save cache on windows which could be restored on any platform * @returns */ function saveCacheV2(paths_1, key_1, options_1) { return __awaiter(this, arguments, void 0, function* (paths, key, options, enableCrossOsArchive = false) { // Override UploadOptions to force the use of Azure // ...options goes first because we want to override the default values // set in UploadOptions with these specific figures options = Object.assign(Object.assign({}, options), { uploadChunkSize: 64 * 1024 * 1024, uploadConcurrency: 8, useAzureSdk: true }); const compressionMethod = yield getCompressionMethod(); const twirpClient = internalCacheTwirpClient(); let cacheId = -1; const cachePaths = yield resolvePaths(paths); debug('Cache Paths:'); debug(`${JSON.stringify(cachePaths)}`); if (cachePaths.length === 0) { throw new Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`); } const archiveFolder = yield createTempDirectory(); const archivePath = path.join(archiveFolder, getCacheFileName(compressionMethod)); debug(`Archive Path: ${archivePath}`); try { yield createTar(archiveFolder, cachePaths, compressionMethod); if (isDebug()) { yield listTar(archivePath, compressionMethod); } const archiveFileSize = getArchiveFileSizeInBytes(archivePath); debug(`File Size: ${archiveFileSize}`); // Set the archive size in the options, will be used to display the upload progress options.archiveSizeBytes = archiveFileSize; debug('Reserving Cache'); const version = getCacheVersion(paths, compressionMethod, enableCrossOsArchive); const request = { key, version }; let signedUploadUrl; try { const response = yield twirpClient.CreateCacheEntry(request); if (!response.ok) { if (response.message) { warning(`Cache reservation failed: ${response.message}`); } throw new Error(response.message || 'Response was not ok'); } signedUploadUrl = response.signedUploadUrl; } catch (error) { debug(`Failed to reserve cache: ${error}`); throw new ReserveCacheError(`Unable to reserve cache with key ${key}, another job may be creating this cache.`); } debug(`Attempting to upload cache located at: ${archivePath}`); yield saveCache$1(cacheId, archivePath, signedUploadUrl, options); const finalizeRequest = { key, version, sizeBytes: `${archiveFileSize}` }; const finalizeResponse = yield twirpClient.FinalizeCacheEntryUpload(finalizeRequest); debug(`FinalizeCacheEntryUploadResponse: ${finalizeResponse.ok}`); if (!finalizeResponse.ok) { if (finalizeResponse.message) { throw new FinalizeCacheError(finalizeResponse.message); } throw new Error(`Unable to finalize cache with key ${key}, another job may be finalizing this cache.`); } cacheId = parseInt(finalizeResponse.entryId); } catch (error$1) { const typedError = error$1; if (typedError.name === ValidationError.name) { throw error$1; } else if (typedError.name === ReserveCacheError.name) { info(`Failed to save: ${typedError.message}`); } else if (typedError.name === FinalizeCacheError.name) { warning(typedError.message); } else { // Log server errors (5xx) as errors, all other errors as warnings if (typedError instanceof HttpClientError && typeof typedError.statusCode === 'number' && typedError.statusCode >= 500) { error(`Failed to save: ${typedError.message}`); } else { warning(`Failed to save: ${typedError.message}`); } } } finally { // Try to delete the archive to save space try { yield unlinkFile(archivePath); } catch (error) { debug(`Failed to delete archive: ${error}`); } } return cacheId; }); } export { FinalizeCacheError, ReserveCacheError, ValidationError, isFeatureAvailable, restoreCache, saveCache };