diff --git a/file/.npmignore b/file/.npmignore new file mode 100644 index 0000000..d7bc9af --- /dev/null +++ b/file/.npmignore @@ -0,0 +1,50 @@ +# browser # +browser/azure-storage.file.js + +# dist-esm # +!dist-esm/lib/**/*.js +dist-esm/test +dist-esm/samples + +# dist-test # +dist-test/ + +# Node # +node_modules/ + +# Samples # +samples/ + +# Swagger # +swagger/ + +# typings # +!typings/lib/**/*.d.ts +typings/test +typings/samples + +# git # +.git* + +# Test # +test/ + +# Others # +.vscode/ +.idea/ +.travis.yml +.gitignore +gulpfile.js +.git +.DS_Store +tsconfig.json +tslint.json +*.js.map +*.zip +package-lock.json +karma.conf.js +temp +gulpfile.js +rollup.config.js +rollup.test.config.js +*.html \ No newline at end of file diff --git a/file/BreakingChanges.md b/file/BreakingChanges.md new file mode 100644 index 0000000..ca1e03e --- /dev/null +++ b/file/BreakingChanges.md @@ -0,0 +1 @@ +# Breaking Changes \ No newline at end of file diff --git a/file/ChangeLog.md b/file/ChangeLog.md new file mode 100644 index 0000000..c013d80 --- /dev/null +++ b/file/ChangeLog.md @@ -0,0 +1,5 @@ +# Changelog + +2018.11 Version 10.0.0-preview + +* Initial Release. API version 2018-03-28 supported. Please see the README for information on the new design. diff --git a/file/LICENSE b/file/LICENSE new file mode 100644 index 0000000..2107107 --- /dev/null +++ b/file/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/file/README.md b/file/README.md new file mode 100644 index 0000000..c4b2642 --- /dev/null +++ b/file/README.md @@ -0,0 +1,148 @@ +# Azure Storage SDK V10 for JavaScript - File + +- [![npm version](https://badge.fury.io/js/%40azure%2Fstorage-file.svg)](https://badge.fury.io/js/%40azure%2Fstorage-file) +- [API Reference documentation](https://docs.microsoft.com/en-us/javascript/api/%40azure/storage-file/index?view=azure-node-preview) + +## Introduction + +This project provides a SDK in JavaScript that makes it easy to consume Microsoft Azure Storage services. + +Please note that this version of the SDK is a compete overhaul of the current [Azure Storage SDK for Node.js and JavaScript in Browsers](https://github.com/azure/azure-storage-node), and is based on the new Storage SDK architecture. + +### Features + +- File Storage + - Get/Set File Service Properties + - Create/List/Delete File Shares + - Create/List/Delete File Directories + - Create/Read/List/Update/Delete Files +- Features new + - Asynchronous I/O for all operations using the async methods + - HttpPipeline which enables a high degree of per-request configurability + - 1-to-1 correlation with the Storage REST API for clarity and simplicity + +### Compatibility + +This SDK is compatible with Node.js and browsers, and validated against LTS Node.js versions (>=6.5) and latest versions of Chrome, Firefox and Edge. + +#### Compatible with IE11 + +You need polyfills to make this library work with IE11. The easiest way is to use [@babel/polyfill](https://babeljs.io/docs/en/babel-polyfill), or [polyfill service](https://polyfill.io/v2/docs/). +Or you can load separate polyfills for missed ES feature(s). +This library depends on following ES6 features which need external polyfills loaded. + +- `Promise` +- `String.prototype.startsWith` +- `String.prototype.endsWith` +- `String.prototype.repeat` +- `String.prototype.includes` + +#### Differences between Node.js and browsers + +There are differences between Node.js and browsers runtime. When getting start with this SDK, pay attention to APIs or classes marked with _"ONLY AVAILABLE IN NODE.JS RUNTIME"_ or _"ONLY AVAILABLE IN BROWSERS"_. + +##### Following features, interfaces, classes or functions are only available in Node.js + +- Shared Key Authorization based on account name and account key + - `SharedKeyCredential` +- Shared Access Signature(SAS) generation + - `generateAccountSASQueryParameters()` + - `generateFileSASQueryParameters()` +- Parallel uploading and downloading + - `uploadFileToBlockFile()` + - `uploadStreamToBlockFile()` + - `downloadFileToBuffer()` + +##### Following features, interfaces, classes or functions are only available in browsers + +- Parallel uploading and downloading + - `uploadBrowserDataToFile()` + +## Getting Started + +### NPM + +The preferred way to install the Azure Storage SDK for JavaScript is to use the npm package manager. Simply type the following into a terminal window: + +```bash +npm install @azure/storage-file +``` + +In your TypeScript or JavaScript file, import via following: + +```JavaScript +import * as Azure from "@azure/storage-file"; +``` + +Or + +```JavaScript +const Azure = require("@azure/storage-file"); +``` + +### JavaScript Bundle + +To use the SDK with JS bundle in the browsers, simply add a script tag to your HTML pages pointing to the downloaded JS bundle file(s): + +```html + +``` + +The JS bundled file is compatible with [UMD](https://github.com/umdjs/umd) standard, if no module system found, following global variable(s) will be exported: + +- `azfile` + +#### Download + +Download latest released JS bundles from links in the [GitHub release page](https://github.com/Azure/azure-storage-js/releases). Or from following links directly: + +- File [https://aka.ms/downloadazurestoragejsfile](https://aka.ms/downloadazurestoragejsfile) + +### CORS + +You need to set up [Cross-Origin Resource Sharing (CORS)](https://docs.microsoft.com/zh-cn/rest/api/storageservices/cross-origin-resource-sharing--cors--support-for-the-azure-storage-services) rules for your storage account if you need to develop for browsers. Go to Azure portal and Azure Storage Explorer, find your storage account, create new CORS rules for blob/queue/file/table service(s). + +For example, you can create following CORS settings for debugging. But please customize the settings carefully according to your requirements in production environment. + +- Allowed origins: \* +- Allowed verbs: DELETE,GET,HEAD,MERGE,POST,OPTIONS,PUT +- Allowed headers: \* +- Exposed headers: \* +- Maximum age (seconds): 86400 + +## SDK Architecture + +The Azure Storage SDK for JavaScript provides low-level and high-level APIs. + +- ServiceURL, ShareURL, DirectoryURL and FileURL objects provide the low-level API functionality and map one-to-one to the [Azure Storage File REST APIs](https://docs.microsoft.com/en-us/rest/api/storageservices/file-service-rest-api). + +- The high-level APIs provide convenience abstractions such as uploading a large stream to a file (using multiple PutBlock requests). + +## Code Samples + +```javascript +// TODO: +``` + +## More Code Samples + +- [File Storage Examples](https://github.com/azure/azure-storage-js/tree/master/file/samples) +- [File Storage Examples - Test Cases](https://github.com/azure/azure-storage-js/tree/master/file/test/) + +## License + +This project is licensed under MIT. + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/file/gulpfile.js b/file/gulpfile.js new file mode 100644 index 0000000..6f0f146 --- /dev/null +++ b/file/gulpfile.js @@ -0,0 +1,16 @@ +const gulp = require("gulp"); +const zip = require("gulp-zip"); + +const version = require("./package.json").version; +const zipFileName = `azurestoragejs.file-${version}.zip`; + +gulp.task("zip", () => { + return gulp + .src([ + "browser/azure-storage.file.js", + "browser/azure-storage.file.min.js", + "browser/*.txt" + ]) + .pipe(zip(zipFileName)) + .pipe(gulp.dest("browser")); +}); \ No newline at end of file diff --git a/file/karma.conf.js b/file/karma.conf.js new file mode 100644 index 0000000..ece2a53 --- /dev/null +++ b/file/karma.conf.js @@ -0,0 +1,82 @@ +module.exports = function(config) { + config.set({ + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: "./", + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ["mocha"], + + plugins: [ + "karma-mocha", + "karma-mocha-reporter", + "karma-chrome-launcher", + "karma-edge-launcher", + "karma-firefox-launcher", + "karma-ie-launcher", + "karma-env-preprocessor" + ], + + // list of files / patterns to load in the browser + files: [ + // polyfill service supporting IE11 missing features + "https://cdn.polyfill.io/v2/polyfill.min.js?features=Promise,String.prototype.startsWith,String.prototype.endsWith,String.prototype.repeat,String.prototype.includes", + "dist-test/index.browser.js" + ], + + // list of files / patterns to exclude + exclude: [], + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + "**/*.js": ["env"] + }, + + // inject following environment values into browser testing with window.__env__ + // environment values MUST be exported or set with same console running "karma start" + // https://www.npmjs.com/package/karma-env-preprocessor + envPreprocessor: ["ACCOUNT_NAME", "ACCOUNT_SAS"], + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ["mocha"], + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + // 'Chrome', 'Firefox', 'Edge', 'IE' + browsers: ["Chrome"], + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: 1, + + browserNoActivityTimeout: 600000, + + client: { + mocha: { + // change Karma's debug.html to the mocha web reporter + reporter: "html", + timeout: "600000" + } + } + }); +}; diff --git a/file/lib/Aborter.ts b/file/lib/Aborter.ts new file mode 100644 index 0000000..d6b1232 --- /dev/null +++ b/file/lib/Aborter.ts @@ -0,0 +1,290 @@ +import { AbortSignalLike, isNode } from "ms-rest-js"; + +/** + * An aborter instance implements AbortSignal interface, can abort HTTP requests. + * + * - Call Aborter.none to create a new Aborter instance without timeout. + * - Call Aborter.timeout() to create a new Aborter instance with timeout. + * + * For an existing instance aborter: + * - Call aborter.withTimeout() to create and return a child Aborter instance with timeout. + * - Call aborter.withValue(key, value) to create and return a child Aborter instance with key/value pair. + * - Call aborter.abort() to abort current instance and all children instances. + * - Call aborter.getValue(key) to search and get value with corresponding key from current aborter to all parents. + * + * @example + * // Abort without timeout + * await blockBlobURL.upload(Aborter.none, buf, buf.length); + * + * @example + * // Abort container create in 1000ms + * await blockBlobURL.upload(Aborter.timeout(1000), buf, buf.length); + * + * @example + * // Share aborter cross multiple operations in 30s + * // Upload the same data to 2 different data centers at the same time, abort another when any of them is finished + * const aborter = Aborter.timeout(30 * 1000); + * blockBlobURL1.upload(aborter, buf, buf.length).then(aborter.abort); + * blockBlobURL2.upload(aborter, buf, buf.length).then(aborter.abort); + * + * @example + * // Cascaded aborting + * // All operations can't take more than 30 seconds + * const aborter = Aborter.timeout(30 * 1000); + * + * // Following 2 operations can't take more than 25 seconds + * await blockBlobURL.upload(aborter.withTimeout(25 * 1000), buf, buf.length); + * await blockBlobURL.upload(aborter.withTimeout(25 * 1000), buf, buf.length); + * + * @export + * @class Aborter + * @implements {AbortSignalLike} + */ + +export class Aborter implements AbortSignalLike { + /** + * Status of whether aborted or not. + * + * @readonly + * @type {boolean} + * @memberof Aborter + */ + public get aborted(): boolean { + return this._aborted; + } + + /** + * Creates a new Aborter instance without timeout. + * + * @readonly + * @static + * @type {Aborter} + * @memberof Aborter + */ + public static get none(): Aborter { + return new Aborter(undefined, 0); + } + + /** + * Creates a new Aborter instance with timeout in million-seconds. + * Set parameter timeout to 0 will not create a timer. + * + * @static + * @param {number} {timeout} in million-seconds + * @returns {Aborter} + * @memberof Aborter + */ + public static timeout(timeout: number): Aborter { + return new Aborter(undefined, timeout); + } + + /** + * onabort event listener. + * + * @memberof Aborter + */ + public onabort?: ((ev: Event) => any); + + // tslint:disable-next-line:variable-name + private _aborted: boolean = false; + private timer?: any; + private readonly parent?: Aborter; + private readonly children: Aborter[] = []; // When child object calls dispose(), remove child from here + private readonly abortEventListeners: Array< + (this: AbortSignalLike, ev: any) => any + > = []; + // Pipeline proxies need to use "abortSignal as Aborter" in order to access non AbortSignalLike methods + // immutable primitive types + private readonly key?: string; + private readonly value?: string | number | boolean | null; + // private disposed: boolean = false; + + /** + * Private constructor for internal usage, creates an instance of Aborter. + * + * @param {Aborter} [parent] Optional. Parent aborter. + * @param {number} [timeout=0] Optional. Timeout before abort in millisecond, 0 means no timeout. + * @param {string} [key] Optional. Immutable key in string. + * @param {(string | number | boolean | null)} [value] Optional. Immutable value. + * @memberof Aborter + */ + private constructor( + parent?: Aborter, + timeout: number = 0, + key?: string, + value?: string | number | boolean | null + ) { + this.parent = parent; + this.key = key; + this.value = value; + + if (timeout > 0) { + this.timer = setTimeout(() => { + this.abort.call(this); + }, timeout); + + // When called, the active Timeout object will not require the Node.js event loop + // to remain active. If there is no other activity keeping the event loop running, + // the process may exit before the Timeout object's callback is invoked. + if (this.timer && isNode) { + this.timer!.unref(); + } + } + } + + /** + * Create and return a new Aborter instance, which will be appended as a child node of current Aborter. + * Current Aborter instance becomes father node of the new instance. When current or father Aborter node + * triggers timeout event, all children nodes abort event will be triggered too. + * + * When timeout parameter (in millisecond) is larger than 0, the abort event will be triggered when timeout. + * Otherwise, call abort() method to manually abort. + * + * @param {number} {timeout} Timeout in millisecond. + * @returns {Aborter} The new Aborter instance created. + * @memberof Aborter + */ + public withTimeout(timeout: number): Aborter { + const childCancelContext = new Aborter(this, timeout); + this.children.push(childCancelContext); + return childCancelContext; + } + + /** + * Create and return a new Aborter instance, which will be appended as a child node of current Aborter. + * Current Aborter instance becomes father node of the new instance. When current or father Aborter node + * triggers timeout event, all children nodes abort event will be triggered too. + * + * Immutable key value pair will be set into the new created Aborter instance. + * Call getValue() to find out latest value with corresponding key in the chain of + * [current node] -> [parent node] and [grand parent node].... + * + * @param {string} key + * @param {(string | number | boolean | null)} [value] + * @returns {Aborter} + * @memberof Aborter + */ + public withValue( + key: string, + value?: string | number | boolean | null + ): Aborter { + const childCancelContext = new Aborter(this, 0, key, value); + this.children.push(childCancelContext); + return childCancelContext; + } + + /** + * Find out latest value with corresponding key in the chain of + * [current node] -> [parent node] -> [grand parent node] -> ... -> [root node]. + * + * If key is not found, undefined will be returned. + * + * @param {string} key + * @returns {(string | number | boolean | null | undefined)} + * @memberof Aborter + */ + public getValue(key: string): string | number | boolean | null | undefined { + for ( + let parent: Aborter | undefined = this; + parent; + parent = parent.parent + ) { + if (parent.key === key) { + return parent.value; + } + } + return undefined; + } + + /** + * Trigger abort event immediately, the onabort and all abort event listeners will be triggered. + * Will try to trigger abort event for all children Aborter nodes. + * + * - If there is a timeout, the timer will be cancelled. + * - If aborted is true, nothing will happen. + * + * @returns + * @memberof Aborter + */ + public abort() { + if (this.aborted) { + return; + } + this.cancelTimer(); + + if (this.onabort) { + this.onabort.call(this); + } + + this.abortEventListeners.forEach(listener => { + listener.call(this); + }); + + this.children.forEach(child => child.cancelByParent()); + + this._aborted = true; + } + + // public dispose() { + // if (this.disposed || this.aborted) { + // return; + // } + + // this.cancelTimer(); + + // // (parent)A <- B <- C(child), if B disposes, when A abort, C will not abort + // if (this.parent) { + // const index = this.parent.children.indexOf(this); + // if (index > -1) { + // this.parent.children.splice(index, 1); + // } + // } + + // this.disposed = true; + // } + + /** + * Added new "abort" event listener, only support "abort" event. + * + * @param {"abort"} _type Only support "abort" event + * @param {(this: AbortSignalLike, ev: any) => any} listener + * @memberof Aborter + */ + public addEventListener( + // tslint:disable-next-line:variable-name + _type: "abort", + listener: (this: AbortSignalLike, ev: any) => any + ): void { + this.abortEventListeners.push(listener); + } + + /** + * Remove "abort" event listener, only support "abort" event. + * + * @param {"abort"} _type Only support "abort" event + * @param {(this: AbortSignalLike, ev: any) => any} listener + * @memberof Aborter + */ + public removeEventListener( + // tslint:disable-next-line:variable-name + _type: "abort", + listener: (this: AbortSignalLike, ev: any) => any + ): void { + const index = this.abortEventListeners.indexOf(listener); + if (index > -1) { + this.abortEventListeners.splice(index, 1); + } + } + + private cancelByParent() { + // if (!this.disposed) { + this.abort(); + // } + } + + private cancelTimer() { + if (this.timer) { + clearTimeout(this.timer); + } + } +} diff --git a/file/lib/AccountSASPermissions.ts b/file/lib/AccountSASPermissions.ts new file mode 100644 index 0000000..8b8c18d --- /dev/null +++ b/file/lib/AccountSASPermissions.ts @@ -0,0 +1,166 @@ +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * This is a helper class to construct a string representing the permissions granted by an AccountSAS. 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 an + * {@link AccountSASSignatureValues} 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. + * + * @export + * @class AccountSASPermissions + */ +export class AccountSASPermissions { + /** + * Parse initializes the AccountSASPermissions fields from a string. + * + * @static + * @param {string} permissions + * @returns {AccountSASPermissions} + * @memberof AccountSASPermissions + */ + public static parse(permissions: string): AccountSASPermissions { + const accountSASPermissions = new AccountSASPermissions(); + + for (const c of permissions) { + switch (c) { + case "r": + accountSASPermissions.read = true; + break; + case "w": + accountSASPermissions.write = true; + break; + case "d": + accountSASPermissions.delete = true; + break; + case "l": + accountSASPermissions.list = true; + break; + case "a": + accountSASPermissions.add = true; + break; + case "c": + accountSASPermissions.create = true; + break; + case "u": + accountSASPermissions.update = true; + break; + case "p": + accountSASPermissions.process = true; + break; + default: + throw new RangeError(`Invalid permission character: ${c}`); + } + } + + return accountSASPermissions; + } + + /** + * Permission to read resources and list queues and tables granted. + * + * @type {boolean} + * @memberof AccountSASPermissions + */ + public read: boolean = false; + + /** + * Permission to write resources granted. + * + * @type {boolean} + * @memberof AccountSASPermissions + */ + public write: boolean = false; + + /** + * Permission to create blobs and files granted. + * + * @type {boolean} + * @memberof AccountSASPermissions + */ + public delete: boolean = false; + + /** + * Permission to list blob containers, blobs, shares, directories, and files granted. + * + * @type {boolean} + * @memberof AccountSASPermissions + */ + public list: boolean = false; + + /** + * Permission to add messages, table entities, and append to blobs granted. + * + * @type {boolean} + * @memberof AccountSASPermissions + */ + public add: boolean = false; + + /** + * Permission to create blobs and files granted. + * + * @type {boolean} + * @memberof AccountSASPermissions + */ + public create: boolean = false; + + /** + * Permissions to update messages and table entities granted. + * + * @type {boolean} + * @memberof AccountSASPermissions + */ + public update: boolean = false; + + /** + * Permission to get and delete messages granted. + * + * @type {boolean} + * @memberof AccountSASPermissions + */ + public process: boolean = false; + + /** + * Produces the SAS permissions string for an Azure Storage account. + * Call this method to set AccountSASSignatureValues Permissions field. + * + * Using this method will guarantee the resource types are in + * an order accepted by the service. + * + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas + * + * @returns {string} + * @memberof AccountSASPermissions + */ + public toString(): string { + // The order of the characters should be as specified here to ensure correctness: + // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas + // Use a string array instead of string concatenating += operator for performance + const permissions: string[] = []; + if (this.read) { + permissions.push("r"); + } + if (this.write) { + permissions.push("w"); + } + if (this.delete) { + permissions.push("d"); + } + if (this.list) { + permissions.push("l"); + } + if (this.add) { + permissions.push("a"); + } + if (this.create) { + permissions.push("c"); + } + if (this.update) { + permissions.push("u"); + } + if (this.process) { + permissions.push("p"); + } + return permissions.join(""); + } +} diff --git a/file/lib/AccountSASResourceTypes.ts b/file/lib/AccountSASResourceTypes.ts new file mode 100644 index 0000000..55defd0 --- /dev/null +++ b/file/lib/AccountSASResourceTypes.ts @@ -0,0 +1,90 @@ +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * This is a helper class to construct a string representing the resources accessible by an AccountSAS. Setting a value + * to true means that any SAS which uses these permissions will grant access to that resource type. Once all the + * values are set, this should be serialized with toString and set as the resources field on an + * {@link AccountSASSignatureValues} object. It is possible to construct the resources string without this class, but + * the order of the resources is particular and this class guarantees correctness. + * + * @export + * @class AccountSASResourceTypes + */ +export class AccountSASResourceTypes { + /** + * Creates an {@link AccountSASResourceType} from the specified resource types string. This method will throw an + * Error if it encounters a character that does not correspond to a valid resource type. + * + * @static + * @param {string} resourceTypes + * @returns {AccountSASResourceTypes} + * @memberof AccountSASResourceTypes + */ + public static parse(resourceTypes: string): AccountSASResourceTypes { + const accountSASResourceTypes = new AccountSASResourceTypes(); + + for (const c of resourceTypes) { + switch (c) { + case "s": + accountSASResourceTypes.service = true; + break; + case "c": + accountSASResourceTypes.container = true; + break; + case "o": + accountSASResourceTypes.object = true; + break; + default: + throw new RangeError(`Invalid resource type: ${c}`); + } + } + + return accountSASResourceTypes; + } + + /** + * Permission to access service level APIs granted. + * + * @type {boolean} + * @memberof AccountSASResourceTypes + */ + public service: boolean = false; + + /** + * Permission to access container level APIs (Blob Containers, Tables, Queues, File Shares) granted. + * + * @type {boolean} + * @memberof AccountSASResourceTypes + */ + public container: boolean = false; + + /** + * Permission to access object level APIs (Blobs, Table Entities, Queue Messages, Files) granted. + * + * @type {boolean} + * @memberof AccountSASResourceTypes + */ + public object: boolean = false; + + /** + * Converts the given resource types to a string. + * + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas + * + * @returns {string} + * @memberof AccountSASResourceTypes + */ + public toString(): string { + const resourceTypes: string[] = []; + if (this.service) { + resourceTypes.push("s"); + } + if (this.container) { + resourceTypes.push("c"); + } + if (this.object) { + resourceTypes.push("o"); + } + return resourceTypes.join(""); + } +} diff --git a/file/lib/AccountSASServices.ts b/file/lib/AccountSASServices.ts new file mode 100644 index 0000000..1dc9f5e --- /dev/null +++ b/file/lib/AccountSASServices.ts @@ -0,0 +1,102 @@ +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * This is a helper class to construct a string representing the services accessible by an AccountSAS. Setting a value + * to true means that any SAS which uses these permissions will grant access to that service. Once all the + * values are set, this should be serialized with toString and set as the services field on an + * {@link AccountSASSignatureValues} object. It is possible to construct the services string without this class, but + * the order of the services is particular and this class guarantees correctness. + * + * @export + * @class AccountSASServices + */ +export class AccountSASServices { + /** + * Creates an {@link AccountSASServices} from the specified services string. This method will throw an + * Error if it encounters a character that does not correspond to a valid service. + * + * @static + * @param {string} services + * @returns {AccountSASServices} + * @memberof AccountSASServices + */ + public static parse(services: string): AccountSASServices { + const accountSASServices = new AccountSASServices(); + + for (const c of services) { + switch (c) { + case "b": + accountSASServices.blob = true; + break; + case "f": + accountSASServices.file = true; + break; + case "q": + accountSASServices.queue = true; + break; + case "t": + accountSASServices.table = true; + break; + default: + throw new RangeError(`Invalid service character: ${c}`); + } + } + + return accountSASServices; + } + + /** + * Permission to access blob resources granted. + * + * @type {boolean} + * @memberof AccountSASServices + */ + public blob: boolean = false; + + /** + * Permission to access file resources granted. + * + * @type {boolean} + * @memberof AccountSASServices + */ + public file: boolean = false; + + /** + * Permission to access queue resources granted. + * + * @type {boolean} + * @memberof AccountSASServices + */ + public queue: boolean = false; + + /** + * Permission to access table resources granted. + * + * @type {boolean} + * @memberof AccountSASServices + */ + public table: boolean = false; + + /** + * Converts the given services to a string. + * + * @returns {string} + * @memberof AccountSASServices + */ + public toString(): string { + const services: string[] = []; + if (this.blob) { + services.push("b"); + } + if (this.table) { + services.push("t"); + } + if (this.queue) { + services.push("q"); + } + if (this.file) { + services.push("f"); + } + return services.join(""); + } +} diff --git a/file/lib/AppendBlobURL.ts b/file/lib/AppendBlobURL.ts new file mode 100644 index 0000000..e3f1d4c --- /dev/null +++ b/file/lib/AppendBlobURL.ts @@ -0,0 +1,179 @@ +import { HttpRequestBody, TransferProgressEvent } from "ms-rest-js"; + +import * as Models from "../lib/generated/models"; +import { Aborter } from "./Aborter"; +import { BlobURL } from "./BlobURL"; +import { ContainerURL } from "./ContainerURL"; +import { AppendBlob } from "./generated/operations"; +import { + IAppendBlobAccessConditions, + IBlobAccessConditions, + IMetadata +} from "./models"; +import { Pipeline } from "./Pipeline"; +import { URLConstants } from "./utils/constants"; +import { appendToURLPath, setURLParameter } from "./utils/utils.common"; + +export interface IAppendBlobCreateOptions { + accessConditions?: IBlobAccessConditions; + blobHTTPHeaders?: Models.BlobHTTPHeaders; + metadata?: IMetadata; +} + +export interface IAppendBlobAppendBlockOptions { + accessConditions?: IAppendBlobAccessConditions; + progress?: (progress: TransferProgressEvent) => void; + transactionalContentMD5?: Uint8Array; +} + +/** + * AppendBlobURL defines a set of operations applicable to append blobs. + * + * @export + * @class AppendBlobURL + * @extends {StorageURL} + */ +export class AppendBlobURL extends BlobURL { + /** + * Creates a AppendBlobURL object from ContainerURL instance. + * + * @static + * @param {ContainerURL} containerURL + * @param {string} blobName + * @returns {AppendBlobURL} + * @memberof AppendBlobURL + */ + public static fromContainerURL( + containerURL: ContainerURL, + blobName: string + ): AppendBlobURL { + return new AppendBlobURL( + appendToURLPath(containerURL.url, blobName), + containerURL.pipeline + ); + } + + /** + * Creates a AppendBlobURL object from BlobURL instance. + * + * @static + * @param {BlobURL} blobURL + * @returns {AppendBlobURL} + * @memberof AppendBlobURL + */ + public static fromBlobURL(blobURL: BlobURL): AppendBlobURL { + return new AppendBlobURL(blobURL.url, blobURL.pipeline); + } + + /** + * appendBlobsContext provided by protocol layer. + * + * @private + * @type {AppendBlobs} + * @memberof AppendBlobURL + */ + private appendBlobContext: AppendBlob; + + /** + * Creates an instance of AppendBlobURL. + * @param {string} url A URL string pointing to Azure Storage append blob, such as + * "https://myaccount.blob.core.windows.net/mycontainer/appendblob". You can + * append a SAS if using AnonymousCredential, such as + * "https://myaccount.blob.core.windows.net/mycontainer/appendblob?sasString". + * @param {Pipeline} pipeline Call StorageURL.newPipeline() to create a default + * pipeline, or provide a customized pipeline. + * @memberof AppendBlobURL + */ + constructor(url: string, pipeline: Pipeline) { + super(url, pipeline); + this.appendBlobContext = new AppendBlob(this.storageClientContext); + } + + /** + * Creates a new AppendBlobURL object identical to the source but with the + * specified request policy pipeline. + * + * @param {Pipeline} pipeline + * @returns {AppendBlobURL} + * @memberof AppendBlobURL + */ + public withPipeline(pipeline: Pipeline): AppendBlobURL { + return new AppendBlobURL(this.url, pipeline); + } + + /** + * Creates a new AppendBlobURL 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 {string} snapshot + * @returns {AppendBlobURL} + * @memberof AppendBlobURL + */ + public withSnapshot(snapshot: string): AppendBlobURL { + return new AppendBlobURL( + setURLParameter( + this.url, + URLConstants.Parameters.SNAPSHOT, + snapshot.length === 0 ? undefined : snapshot + ), + this.pipeline + ); + } + + /** + * Creates a 0-length append blob. Call AppendBlock to append data to an append blob. + * @see https://docs.microsoft.com/rest/api/storageservices/put-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IAppendBlobCreateOptions} [options] + * @returns {Promise} + * @memberof AppendBlobURL + */ + public async create( + aborter: Aborter, + options: IAppendBlobCreateOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.appendBlobContext.create(0, { + abortSignal: aborter, + blobHTTPHeaders: options.blobHTTPHeaders, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + metadata: options.metadata, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions + }); + } + + /** + * Commits a new block of data to the end of the existing append blob. + * @see https://docs.microsoft.com/rest/api/storageservices/append-block + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {HttpRequestBody} body + * @param {number} contentLength + * @param {IAppendBlobAppendBlockOptions} [options] + * @returns {Promise} + * @memberof AppendBlobURL + */ + public async appendBlock( + aborter: Aborter, + body: HttpRequestBody, + contentLength: number, + options: IAppendBlobAppendBlockOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.appendBlobContext.appendBlock(body, contentLength, { + abortSignal: aborter, + appendPositionAccessConditions: + options.accessConditions.appendPositionAccessConditions, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions, + onUploadProgress: options.progress, + transactionalContentMD5: options.transactionalContentMD5 + }); + } +} diff --git a/file/lib/BlobSASPermissions.ts b/file/lib/BlobSASPermissions.ts new file mode 100644 index 0000000..a7d8d15 --- /dev/null +++ b/file/lib/BlobSASPermissions.ts @@ -0,0 +1,117 @@ +/** + * 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 ServiceSASSignatureValues} 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. + * + * @export + * @class BlobSASPermissions + */ +export class BlobSASPermissions { + /** + * Creates a {@link BlobSASPermission} from the specified permissions string. This method will throw an + * Error if it encounters a character that does not correspond to a valid permission. + * + * @static + * @param {string} permissions + * @returns {BlobSASPermissions} + * @memberof BlobSASPermissions + */ + public static parse(permissions: string): BlobSASPermissions { + 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; + default: + throw new RangeError(`Invalid permission: ${char}`); + } + } + + return blobSASPermissions; + } + + /** + * Specifies Read access granted. + * + * @type {boolean} + * @memberof BlobSASPermissions + */ + public read: boolean = false; + + /** + * Specifies Add access granted. + * + * @type {boolean} + * @memberof BlobSASPermissions + */ + public add: boolean = false; + + /** + * Specifies Create access granted. + * + * @type {boolean} + * @memberof BlobSASPermissions + */ + public create: boolean = false; + + /** + * Specifies Write access granted. + * + * @type {boolean} + * @memberof BlobSASPermissions + */ + public write: boolean = false; + + /** + * Specifies Delete access granted. + * + * @type {boolean} + * @memberof BlobSASPermissions + */ + public delete: boolean = false; + + /** + * Converts the given permissions to a string. Using this method will guarantee the permissions are in an + * order accepted by the service. + * + * @returns {string} A string which represents the BlobSASPermissions + * @memberof BlobSASPermissions + */ + public toString(): string { + const permissions: string[] = []; + 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"); + } + return permissions.join(""); + } +} diff --git a/file/lib/BlobURL.ts b/file/lib/BlobURL.ts new file mode 100644 index 0000000..a4a1f7f --- /dev/null +++ b/file/lib/BlobURL.ts @@ -0,0 +1,574 @@ +import { TransferProgressEvent } from "ms-rest-js"; + +import * as Models from "../lib/generated/models"; +import { Aborter } from "./Aborter"; +import { ContainerURL } from "./ContainerURL"; +import { Blob } from "./generated/operations"; +import { rangeToString } from "./IRange"; +import { IBlobAccessConditions, IMetadata } from "./models"; +import { Pipeline } from "./Pipeline"; +import { StorageURL } from "./StorageURL"; +import { URLConstants } from "./utils/constants"; +import { appendToURLPath, setURLParameter } from "./utils/utils.common"; + +export interface IBlobDownloadOptions { + snapshot?: string; + rangeGetContentMD5?: boolean; + blobAccessConditions?: IBlobAccessConditions; + progress?: (progress: TransferProgressEvent) => void; +} + +export interface IBlobGetPropertiesOptions { + blobAccessConditions?: IBlobAccessConditions; +} + +export interface IBlobDeleteOptions { + blobAccessConditions?: IBlobAccessConditions; + deleteSnapshots?: Models.DeleteSnapshotsOptionType; +} + +export interface IBlobSetHTTPHeadersOptions { + blobAccessConditions?: IBlobAccessConditions; + blobHTTPHeaders?: Models.BlobHTTPHeaders; +} + +export interface IBlobSetMetadataOptions { + metadata?: IMetadata; + blobAccessConditions?: IBlobAccessConditions; +} + +export interface IBlobAcquireLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IBlobReleaseLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IBlobRenewLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IBlobChangeLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IBlobBreakLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IBlobCreateSnapshotOptions { + metadata?: IMetadata; + blobAccessConditions?: IBlobAccessConditions; +} + +export interface IBlobStartCopyFromURLOptions { + metadata?: IMetadata; + blobAccessConditions?: IBlobAccessConditions; + sourceModifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IBlobAbortCopyFromURLOptions { + leaseAccessConditions?: Models.LeaseAccessConditions; +} + +export interface IBlobSetTierOptions { + leaseAccessConditions?: Models.LeaseAccessConditions; +} + +/** + * A BlobURL represents a URL to an Azure Storage blob; the blob may be a block blob, + * append blob, or page blob. + * + * @export + * @class BlobURL + * @extends {StorageURL} + */ +export class BlobURL extends StorageURL { + /** + * Creates a BlobURL object from an ContainerURL object. + * + * @static + * @param {ContainerURL} containerURL + * @param {string} blobName + * @returns + * @memberof BlobURL + */ + public static fromContainerURL(containerURL: ContainerURL, blobName: string) { + return new BlobURL( + appendToURLPath(containerURL.url, blobName), + containerURL.pipeline + ); + } + + /** + * blobContext provided by protocol layer. + * + * @private + * @type {Blobs} + * @memberof BlobURL + */ + private blobContext: Blob; + + /** + * Creates an instance of BlobURL. + * @param {string} url A URL string pointing to Azure Storage blob, such as + * "https://myaccount.blob.core.windows.net/mycontainer/blob". You can + * append a SAS if using AnonymousCredential, such as + * "https://myaccount.blob.core.windows.net/mycontainer/blob?sasString". + * @param {Pipeline} pipeline Call StorageURL.newPipeline() to create a default + * pipeline, or provide a customized pipeline. + * @memberof BlobURL + */ + constructor(url: string, pipeline: Pipeline) { + super(url, pipeline); + this.blobContext = new Blob(this.storageClientContext); + } + + /** + * Creates a new BlobURL object identical to the source but with the + * specified request policy pipeline. + * + * @param {Pipeline} pipeline + * @returns {BlobURL} + * @memberof BlobURL + */ + public withPipeline(pipeline: Pipeline): BlobURL { + return new BlobURL(this.url, pipeline); + } + + /** + * Creates a new BlobURL 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 {string} snapshot + * @returns {BlobURL} A new BlobURL object identical to the source but with the specified snapshot timestamp + * @memberof BlobURL + */ + public withSnapshot(snapshot: string): BlobURL { + return new BlobURL( + setURLParameter( + this.url, + URLConstants.Parameters.SNAPSHOT, + snapshot.length === 0 ? undefined : snapshot + ), + this.pipeline + ); + } + + /** + * 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 + * + * WARNING: In Node.js, abort or network error during reading from response stream will NOT + * trigger any error, readable stream will end immediately. You need to check downloaded data + * length when stream ends. + * + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {number} offset From which position of the blob to download, >= 0 + * @param {number} [count] How much data to be downloaded, > 0. Will download to the end when undefined + * @param {IBlobDownloadOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async download( + aborter: Aborter, + offset: number, + count?: number, + options: IBlobDownloadOptions = {} + ): Promise { + options.blobAccessConditions = options.blobAccessConditions || {}; + + const res = await this.blobContext.download({ + abortSignal: aborter, + leaseAccessConditions: options.blobAccessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.blobAccessConditions.modifiedAccessConditions, + onDownloadProgress: options.progress, + range: + offset === 0 && !count ? undefined : rangeToString({ offset, count }), + rangeGetContentMD5: options.rangeGetContentMD5, + snapshot: options.snapshot + }); + + // Default axios based HTTP client cannot abort download stream, manually pause/abort it + // Currently, no error will be triggered when network error or abort during reading from response stream + // TODO: Now need to manually validate the date length when stream ends, add download retry in the future + if (res.readableStreamBody) { + aborter.addEventListener("abort", () => { + if (res.readableStreamBody) { + res.readableStreamBody.pause(); + } + }); + } + + return res; + } + + /** + * 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://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-properties + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IBlobGetPropertiesOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async getProperties( + aborter: Aborter, + options: IBlobGetPropertiesOptions = {} + ): Promise { + options.blobAccessConditions = options.blobAccessConditions || {}; + return this.blobContext.getProperties({ + abortSignal: aborter, + leaseAccessConditions: options.blobAccessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.blobAccessConditions.modifiedAccessConditions + }); + } + + /** + * 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://docs.microsoft.com/en-us/rest/api/storageservices/delete-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IBlobDeleteOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async delete( + aborter: Aborter, + options: IBlobDeleteOptions = {} + ): Promise { + options.blobAccessConditions = options.blobAccessConditions || {}; + return this.blobContext.deleteMethod({ + abortSignal: aborter, + deleteSnapshots: options.deleteSnapshots, + leaseAccessConditions: options.blobAccessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.blobAccessConditions.modifiedAccessConditions + }); + } + + /** + * 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://docs.microsoft.com/en-us/rest/api/storageservices/undelete-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @returns {Promise} + * @memberof BlobURL + */ + public async undelete( + aborter: Aborter + ): Promise { + return this.blobContext.undelete({ + abortSignal: aborter + }); + } + + /** + * Sets system properties on the blob. + * + * If no option provided, or no value provided for the blob HTTP headers in the options, + * these blob HTTP headers without a value will be cleared. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-properties + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IBlobSetHTTPHeadersOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async setHTTPHeaders( + aborter: Aborter, + options: IBlobSetHTTPHeadersOptions = {} + ): Promise { + options.blobAccessConditions = options.blobAccessConditions || {}; + return this.blobContext.setHTTPHeaders({ + abortSignal: aborter, + blobHTTPHeaders: options.blobHTTPHeaders, + leaseAccessConditions: options.blobAccessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.blobAccessConditions.modifiedAccessConditions + }); + } + + /** + * 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 option parameter, the blob + * metadata will be removed. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-metadata + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IBlobSetMetadataOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async setMetadata( + aborter: Aborter, + options: IBlobSetMetadataOptions = {} + ): Promise { + options.blobAccessConditions = options.blobAccessConditions || {}; + return this.blobContext.setMetadata({ + abortSignal: aborter, + leaseAccessConditions: options.blobAccessConditions.leaseAccessConditions, + metadata: options.metadata, + modifiedAccessConditions: + options.blobAccessConditions.modifiedAccessConditions + }); + } + + /** + * Establishes and manages a lock on a blob for write and delete operations. + * The lock duration can be 15 to 60 seconds, or can be infinite. + * In versions prior to 2012-02-12, the lock duration is 60 seconds. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} proposedLeaseId Can be specified in any valid GUID string format + * @param {number} duration The lock duration can be 15 to 60 seconds, or can be infinite + * @param {IBlobAcquireLeaseOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async acquireLease( + aborter: Aborter, + proposedLeaseId: string, + duration: number, + options: IBlobAcquireLeaseOptions = {} + ): Promise { + return this.blobContext.acquireLease({ + abortSignal: aborter, + duration, + modifiedAccessConditions: options.modifiedAccessConditions, + proposedLeaseId + }); + } + + /** + * To free the lease if it is no longer needed so that another client may immediately + * acquire a lease against the blob. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} leaseId + * @param {IBlobReleaseLeaseOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async releaseLease( + aborter: Aborter, + leaseId: string, + options: IBlobReleaseLeaseOptions = {} + ): Promise { + return this.blobContext.releaseLease(leaseId, { + abortSignal: aborter, + modifiedAccessConditions: options.modifiedAccessConditions + }); + } + + /** + * To renew an existing lease. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} leaseId + * @param {IBlobRenewLeaseOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async renewLease( + aborter: Aborter, + leaseId: string, + options: IBlobRenewLeaseOptions = {} + ): Promise { + return this.blobContext.renewLease(leaseId, { + abortSignal: aborter, + modifiedAccessConditions: options.modifiedAccessConditions + }); + } + + /** + * To change the ID of an existing lease. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} leaseId + * @param {string} proposedLeaseId + * @param {IBlobChangeLeaseOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async changeLease( + aborter: Aborter, + leaseId: string, + proposedLeaseId: string, + options: IBlobChangeLeaseOptions = {} + ): Promise { + return this.blobContext.changeLease(leaseId, proposedLeaseId, { + abortSignal: aborter, + modifiedAccessConditions: options.modifiedAccessConditions + }); + } + + /** + * To end the lease but ensure that another client cannot acquire a new lease + * until the current lease period has expired. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {number} [breakPeriod] + * @param {IBlobBreakLeaseOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async breakLease( + aborter: Aborter, + breakPeriod?: number, + options: IBlobBreakLeaseOptions = {} + ): Promise { + return this.blobContext.breakLease({ + abortSignal: aborter, + breakPeriod, + modifiedAccessConditions: options.modifiedAccessConditions + }); + } + + /** + * Creates a read-only snapshot of a blob. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/snapshot-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IBlobCreateSnapshotOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async createSnapshot( + aborter: Aborter, + options: IBlobCreateSnapshotOptions = {} + ): Promise { + options.blobAccessConditions = options.blobAccessConditions || {}; + return this.blobContext.createSnapshot({ + abortSignal: aborter, + leaseAccessConditions: options.blobAccessConditions.leaseAccessConditions, + metadata: options.metadata, + modifiedAccessConditions: + options.blobAccessConditions.modifiedAccessConditions + }); + } + + /** + * 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://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} copySource + * @param {IBlobStartCopyFromURLOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async startCopyFromURL( + aborter: Aborter, + copySource: string, + options: IBlobStartCopyFromURLOptions = {} + ): Promise { + options.blobAccessConditions = options.blobAccessConditions || {}; + options.sourceModifiedAccessConditions = + options.sourceModifiedAccessConditions || {}; + + return this.blobContext.startCopyFromURL(copySource, { + abortSignal: aborter, + leaseAccessConditions: options.blobAccessConditions.leaseAccessConditions, + metadata: options.metadata, + modifiedAccessConditions: + options.blobAccessConditions.modifiedAccessConditions, + sourceModifiedAccessConditions: { + sourceIfMatch: options.sourceModifiedAccessConditions.ifMatch, + sourceIfModifiedSince: + options.sourceModifiedAccessConditions.ifModifiedSince, + sourceIfNoneMatch: options.sourceModifiedAccessConditions.ifNoneMatch, + sourceIfUnmodifiedSince: + options.sourceModifiedAccessConditions.ifUnmodifiedSince + } + }); + } + + /** + * Aborts a pending Copy Blob operation, and leaves a destination blob with zero + * length and full metadata. Version 2012-02-12 and newer. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/abort-copy-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} copyId + * @param {IBlobAbortCopyFromURLOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async abortCopyFromURL( + aborter: Aborter, + copyId: string, + options: IBlobAbortCopyFromURLOptions = {} + ): Promise { + return this.blobContext.abortCopyFromURL(copyId, { + abortSignal: aborter, + leaseAccessConditions: options.leaseAccessConditions + }); + } + + /** + * 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://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tier + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {Models.AccessTier} tier + * @param {IBlobSetTierOptions} [options] + * @returns {Promise} + * @memberof BlobURL + */ + public async setTier( + aborter: Aborter, + tier: Models.AccessTier, + options: IBlobSetTierOptions = {} + ): Promise { + return await this.blobContext.setTier(tier, { + abortSignal: aborter, + leaseAccessConditions: options.leaseAccessConditions + }); + } +} diff --git a/file/lib/BlockBlobURL.ts b/file/lib/BlockBlobURL.ts new file mode 100644 index 0000000..75921aa --- /dev/null +++ b/file/lib/BlockBlobURL.ts @@ -0,0 +1,313 @@ +import { HttpRequestBody, TransferProgressEvent } from "ms-rest-js"; + +import * as Models from "../lib/generated/models"; +import { Aborter } from "./Aborter"; +import { BlobURL } from "./BlobURL"; +import { ContainerURL } from "./ContainerURL"; +import { BlockBlob } from "./generated/operations"; +import { IRange, rangeToString } from "./IRange"; +import { IBlobAccessConditions, IMetadata } from "./models"; +import { Pipeline } from "./Pipeline"; +import { URLConstants } from "./utils/constants"; +import { appendToURLPath, setURLParameter } from "./utils/utils.common"; + +export interface IBlockBlobUploadOptions { + accessConditions?: IBlobAccessConditions; + blobHTTPHeaders?: Models.BlobHTTPHeaders; + metadata?: IMetadata; + progress?: (progress: TransferProgressEvent) => void; +} + +export interface IBlockBlobStageBlockOptions { + leaseAccessConditions?: Models.LeaseAccessConditions; + progress?: (progress: TransferProgressEvent) => void; + transactionalContentMD5?: Uint8Array; +} + +export interface IBlockBlobStageBlockFromURLOptions { + range?: IRange; + leaseAccessConditions?: Models.LeaseAccessConditions; + sourceContentMD5?: Uint8Array; +} + +export interface IBlockBlobCommitBlockListOptions { + accessConditions?: IBlobAccessConditions; + blobHTTPHeaders?: Models.BlobHTTPHeaders; + metadata?: IMetadata; +} + +export interface IBlockBlobGetBlockListOptions { + leaseAccessConditions?: Models.LeaseAccessConditions; +} + +/** + * BlockBlobURL defines a set of operations applicable to block blobs. + * + * @export + * @class BlockBlobURL + * @extends {StorageURL} + */ +export class BlockBlobURL extends BlobURL { + /** + * Creates a BlockBlobURL object from ContainerURL instance. + * + * @static + * @param {ContainerURL} containerURL + * @param {string} blobName + * @returns {BlockBlobURL} + * @memberof BlockBlobURL + */ + public static fromContainerURL( + containerURL: ContainerURL, + blobName: string + ): BlockBlobURL { + return new BlockBlobURL( + appendToURLPath(containerURL.url, blobName), + containerURL.pipeline + ); + } + + /** + * Creates a BlockBlobURL object from BlobURL instance. + * + * @static + * @param {BlobURL} blobURL + * @returns {BlockBlobURL} + * @memberof BlockBlobURL + */ + public static fromBlobURL(blobURL: BlobURL): BlockBlobURL { + return new BlockBlobURL(blobURL.url, blobURL.pipeline); + } + + /** + * blockBlobContext provided by protocol layer. + * + * @private + * @type {BlockBlobs} + * @memberof BlockBlobURL + */ + private blockBlobContext: BlockBlob; + + /** + * Creates an instance of BlockBlobURL. + * @param {string} url A URL string pointing to Azure Storage block blob, such as + * "https://myaccount.blob.core.windows.net/mycontainer/blockblob". You can + * append a SAS if using AnonymousCredential, such as + * "https://myaccount.blob.core.windows.net/mycontainer/blockblob?sasString". + * @param {Pipeline} pipeline Call StorageURL.newPipeline() to create a default + * pipeline, or provide a customized pipeline. + * @memberof BlockBlobURL + */ + constructor(url: string, pipeline: Pipeline) { + super(url, pipeline); + this.blockBlobContext = new BlockBlob(this.storageClientContext); + } + + /** + * Creates a new BlockBlobURL object identical to the source but with the + * specified request policy pipeline. + * + * @param {Pipeline} pipeline + * @returns {BlockBlobURL} + * @memberof BlockBlobURL + */ + public withPipeline(pipeline: Pipeline): BlockBlobURL { + return new BlockBlobURL(this.url, pipeline); + } + + /** + * Creates a new BlockBlobURL 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 {string} snapshot + * @returns {BlockBlobURL} + * @memberof BlockBlobURL + */ + public withSnapshot(snapshot: string): BlockBlobURL { + return new BlockBlobURL( + setURLParameter( + this.url, + URLConstants.Parameters.SNAPSHOT, + snapshot.length === 0 ? undefined : snapshot + ), + this.pipeline + ); + } + + /** + * 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 stageBlock and commitBlockList. + * + * This is a non-parallel uploading method, please use uploadFileToBlockBlob(), + * uploadStreamToBlockBlob() or uploadBrowserDataToBlockBlob() for better performance + * with concurrency uploading. + * + * @see https://docs.microsoft.com/rest/api/storageservices/put-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {HttpRequestBody} body + * @param {number} contentLength + * @param {IBlockBlobUploadOptions} [options] + * @returns {Promise} + * @memberof BlockBlobURL + */ + public async upload( + aborter: Aborter, + body: HttpRequestBody, + contentLength: number, + options: IBlockBlobUploadOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.blockBlobContext.upload(body, contentLength, { + abortSignal: aborter, + blobHTTPHeaders: options.blobHTTPHeaders, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + metadata: options.metadata, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions, + onUploadProgress: options.progress + }); + } + + /** + * Uploads the specified block to the block blob's "staging area" to be later + * committed by a call to commitBlockList. + * @see https://docs.microsoft.com/rest/api/storageservices/put-block + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} blockId A 64-byte value that is base64-encoded + * @param {HttpRequestBody} body + * @param {number} contentLength + * @param {IBlockBlobStageBlockOptions} [options] + * @returns {Promise} + * @memberof BlockBlobURL + */ + public async stageBlock( + aborter: Aborter, + blockId: string, + body: HttpRequestBody, + contentLength: number, + options: IBlockBlobStageBlockOptions = {} + ): Promise { + return this.blockBlobContext.stageBlock(blockId, contentLength, body, { + abortSignal: aborter, + leaseAccessConditions: options.leaseAccessConditions, + onUploadProgress: options.progress, + transactionalContentMD5: options.transactionalContentMD5 + }); + } + + /** + * 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://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} blockId A 64-byte value that is base64-encoded + * @param {string} 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 {number} offset From which position of the blob to download, >= 0 + * @param {number} [count] How much data to be downloaded, > 0. Will download to the end when undefined + * @param {IBlockBlobStageBlockFromURLOptions} [options={}] + * @returns {Promise} + * @memberof BlockBlobURL + */ + public async stageBlockFromURL( + aborter: Aborter, + blockId: string, + sourceURL: string, + offset: number, + count?: number, + options: IBlockBlobStageBlockFromURLOptions = {} + ): Promise { + return this.blockBlobContext.stageBlockFromURL(blockId, 0, sourceURL, { + abortSignal: aborter, + leaseAccessConditions: options.leaseAccessConditions, + sourceContentMD5: options.sourceContentMD5, + sourceRange: + offset === 0 && !count ? undefined : rangeToString({ offset, count }) + }); + } + + /** + * 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 stageBlock operation. You can call 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://docs.microsoft.com/rest/api/storageservices/put-block-list + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string[]} blocks Array of 64-byte value that is base64-encoded + * @param {IBlockBlobCommitBlockListOptions} [options] + * @returns {Promise} + * @memberof BlockBlobURL + */ + public async commitBlockList( + aborter: Aborter, + blocks: string[], + options: IBlockBlobCommitBlockListOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.blockBlobContext.commitBlockList( + { latest: blocks }, + { + abortSignal: aborter, + blobHTTPHeaders: options.blobHTTPHeaders, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + metadata: options.metadata, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions + } + ); + } + + /** + * Returns the list of blocks that have been uploaded as part of a block blob + * using the specified block list filter. + * @see https://docs.microsoft.com/rest/api/storageservices/get-block-list + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {Models.BlockListType} listType + * @param {IBlockBlobGetBlockListOptions} [options] + * @returns {Promise} + * @memberof BlockBlobURL + */ + public async getBlockList( + aborter: Aborter, + listType: Models.BlockListType, + options: IBlockBlobGetBlockListOptions = {} + ): Promise { + const res = await this.blockBlobContext.getBlockList(listType, { + abortSignal: aborter, + leaseAccessConditions: options.leaseAccessConditions + }); + + if (!res.committedBlocks) { + res.committedBlocks = []; + } + + if (!res.uncommittedBlocks) { + res.uncommittedBlocks = []; + } + + return res; + } +} diff --git a/file/lib/BrowserPolicyFactory.ts b/file/lib/BrowserPolicyFactory.ts new file mode 100644 index 0000000..db09627 --- /dev/null +++ b/file/lib/BrowserPolicyFactory.ts @@ -0,0 +1,23 @@ +import { + RequestPolicy, + RequestPolicyFactory, + RequestPolicyOptions +} from "ms-rest-js"; + +import { BrowserPolicy } from "./policies/BrowserPolicy"; + +/** + * BrowserPolicyFactory is a factory class helping generating BrowserPolicy objects. + * + * @export + * @class BrowserPolicyFactory + * @implements {RequestPolicyFactory} + */ +export class BrowserPolicyFactory implements RequestPolicyFactory { + public create( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions + ): BrowserPolicy { + return new BrowserPolicy(nextPolicy, options); + } +} diff --git a/file/lib/ContainerSASPermissions.ts b/file/lib/ContainerSASPermissions.ts new file mode 100644 index 0000000..2f7c3ff --- /dev/null +++ b/file/lib/ContainerSASPermissions.ts @@ -0,0 +1,132 @@ +/** + * 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 ServiceSASSignatureValues} 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. + * + * @export + * @class ContainerSASPermissions + */ +export 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. + * + * @static + * @param {string} permissions + * @returns + * @memberof ContainerSASPermissions + */ + public static parse(permissions: string) { + 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; + default: + throw new RangeError(`Invalid permission ${char}`); + } + } + + return containerSASPermissions; + } + + /** + * Specifies Read access granted. + * + * @type {boolean} + * @memberof ContainerSASPermissions + */ + public read: boolean = false; + + /** + * Specifies Add access granted. + * + * @type {boolean} + * @memberof ContainerSASPermissions + */ + public add: boolean = false; + + /** + * Specifies Create access granted. + * + * @type {boolean} + * @memberof ContainerSASPermissions + */ + public create: boolean = false; + + /** + * Specifies Write access granted. + * + * @type {boolean} + * @memberof ContainerSASPermissions + */ + public write: boolean = false; + + /** + * Specifies Delete access granted. + * + * @type {boolean} + * @memberof ContainerSASPermissions + */ + public delete: boolean = false; + + /** + * Specifies List access granted. + * + * @type {boolean} + * @memberof ContainerSASPermissions + */ + public list: boolean = 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://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas + * + * @returns {string} + * @memberof ContainerSASPermissions + */ + public toString(): string { + const permissions: string[] = []; + 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.list) { + permissions.push("l"); + } + return permissions.join(""); + } +} diff --git a/file/lib/ContainerURL.ts b/file/lib/ContainerURL.ts new file mode 100644 index 0000000..3aea965 --- /dev/null +++ b/file/lib/ContainerURL.ts @@ -0,0 +1,613 @@ +import { HttpResponse } from "ms-rest-js"; +import * as Models from "../lib/generated/models"; +import { Aborter } from "./Aborter"; +import { Container } from "./generated/operations"; +import { IContainerAccessConditions, IMetadata } from "./models"; +import { Pipeline } from "./Pipeline"; +import { ServiceURL } from "./ServiceURL"; +import { StorageURL } from "./StorageURL"; +import { ETagNone } from "./utils/constants"; +import { appendToURLPath, truncatedISO8061Date } from "./utils/utils.common"; + +export interface IContainerCreateOptions { + metadata?: IMetadata; + access?: Models.PublicAccessType; +} + +export interface IContainerGetPropertiesOptions { + leaseAccessConditions?: Models.LeaseAccessConditions; +} + +export interface IContainerDeleteMethodOptions { + containerAccessConditions?: IContainerAccessConditions; +} + +export interface IContainerSetMetadataOptions { + metadata?: IMetadata; + containerAccessConditions?: IContainerAccessConditions; +} + +export interface IContainerGetAccessPolicyOptions { + leaseAccessConditions?: Models.LeaseAccessConditions; +} + +export interface ISignedIdentifier { + /** + * @member {string} id a unique id + */ + id: string; + /** + * @member {AccessPolicy} accessPolicy + */ + accessPolicy: { + /** + * @member {Date} start the date-time the policy is active. A validate ISO string format, or Date + */ + start: Date; + /** + * @member {string} expiry the date-time the policy expires. A validate ISO string format, or Date + */ + expiry: Date; + /** + * @member {string} permission the permissions for the acl policy + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-container-acl + */ + permission: string; + }; +} + +export declare type ContainerGetAccessPolicyResponse = { + signedIdentifiers: ISignedIdentifier[]; +} & Models.ContainerGetAccessPolicyHeaders & { + /** + * The underlying HTTP response. + */ + _response: HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: Models.ContainerGetAccessPolicyHeaders; + /** + * The response body as text (string format) + */ + bodyAsText: string; + /** + * The response body as parsed JSON or XML + */ + parsedBody: Models.SignedIdentifier[]; + }; + }; + +export interface IContainerSetAccessPolicyOptions { + containerAccessConditions?: IContainerAccessConditions; +} + +export interface IContainerAcquireLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IContainerReleaseLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IContainerRenewLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IContainerBreakLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IContainerChangeLeaseOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +export interface IContainerListBlobsSegmentOptions { + /** + * @member {string} [prefix] Filters the results to return only containers + * whose name begins with the specified prefix. + */ + prefix?: string; + /** + * @member {number} [maxresults] Specifies the maximum number of containers + * to return. If the request does not specify maxresults, or specifies a + * value greater than 5000, the server will return up to 5000 items. Note + * that if the listing operation crosses a partition boundary, then the + * service will return a continuation token for retrieving the remainder of + * the results. For this reason, it is possible that the service will return + * fewer results than specified by maxresults, or than the default of 5000. + */ + maxresults?: number; + /** + * @member {ListBlobsIncludeItem[]} [include] Include this parameter to + * specify one or more datasets to include in the response. + */ + include?: Models.ListBlobsIncludeItem[]; +} + +/** + * A ContainerURL represents a URL to the Azure Storage container allowing you to manipulate its blobs. + * + * @export + * @class ContainerURL + * @extends {StorageURL} + */ +export class ContainerURL extends StorageURL { + /** + * Creates a ContainerURL object from ServiceURL + * @param serviceURL + * @param containerName + */ + public static fromServiceURL( + serviceURL: ServiceURL, + containerName: string + ): ContainerURL { + return new ContainerURL( + appendToURLPath(serviceURL.url, containerName), + serviceURL.pipeline + ); + } + + /** + * containersContext provided by protocol layer. + * + * @private + * @type {Containers} + * @memberof ContainerURL + */ + private containerContext: Container; + + /** + * Creates an instance of ContainerURL. + * @param {string} url A URL string pointing to Azure Storage blob container, such as + * "https://myaccount.blob.core.windows.net/mycontainer". You can + * append a SAS if using AnonymousCredential, such as + * "https://myaccount.blob.core.windows.net/mycontainer?sasString". + * @param {Pipeline} pipeline Call StorageURL.newPipeline() to create a default + * pipeline, or provide a customized pipeline. + * @memberof ContainerURL + */ + constructor(url: string, pipeline: Pipeline) { + super(url, pipeline); + this.containerContext = new Container(this.storageClientContext); + } + + /** + * Creates a new ContainerURL object identical to the source but with the + * specified request policy pipeline. + * + * @param {Pipeline} pipeline + * @returns {ContainerURL} + * @memberof ContainerURL + */ + public withPipeline(pipeline: Pipeline): ContainerURL { + return new ContainerURL(this.url, pipeline); + } + + /** + * Creates a new container under the specified account. If the container with + * the same name already exists, the operation fails. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/create-container + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IContainerCreateOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async create( + aborter: Aborter, + options: IContainerCreateOptions = {} + ): Promise { + // Spread operator in destructuring assignments, + // this will filter out unwanted properties from the response object into result object + return this.containerContext.create({ + ...options, + abortSignal: aborter + }); + } + + /** + * Returns all user-defined metadata and system properties for the specified + * container. The data returned does not include the container's list of blobs. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/get-container-properties + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IContainersGetPropertiesOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async getProperties( + aborter: Aborter, + options: IContainerGetPropertiesOptions = {} + ): Promise { + if (!options.leaseAccessConditions) { + options.leaseAccessConditions = {}; + } + + return this.containerContext.getProperties({ + abortSignal: aborter, + ...options.leaseAccessConditions + }); + } + + /** + * Marks the specified container for deletion. The container and any blobs + * contained within it are later deleted during garbage collection. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/delete-container + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {Models.ContainersDeleteMethodOptionalParams} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async delete( + aborter: Aborter, + options: IContainerDeleteMethodOptions = {} + ): Promise { + if (!options.containerAccessConditions) { + options.containerAccessConditions = {}; + } + + if (!options.containerAccessConditions.modifiedAccessConditions) { + options.containerAccessConditions.modifiedAccessConditions = {}; + } + + if (!options.containerAccessConditions.leaseAccessConditions) { + options.containerAccessConditions.leaseAccessConditions = {}; + } + + if ( + (options.containerAccessConditions.modifiedAccessConditions.ifMatch && + options.containerAccessConditions.modifiedAccessConditions.ifMatch !== + ETagNone) || + (options.containerAccessConditions.modifiedAccessConditions.ifNoneMatch && + options.containerAccessConditions.modifiedAccessConditions + .ifNoneMatch !== ETagNone) + ) { + throw new RangeError( + "the IfMatch and IfNoneMatch access conditions must have their default\ + values because they are ignored by the service" + ); + } + + return this.containerContext.deleteMethod({ + abortSignal: aborter, + leaseAccessConditions: + options.containerAccessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.containerAccessConditions.modifiedAccessConditions + }); + } + + /** + * Sets one or more user-defined name-value pairs for the specified container. + * + * If no option provided, or no metadata defined in the option parameter, the container + * metadata will be removed. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-container-metadata + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IContainerSetMetadataOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async setMetadata( + aborter: Aborter, + options: IContainerSetMetadataOptions = {} + ): Promise { + if (!options.containerAccessConditions) { + options.containerAccessConditions = {}; + } + + if (!options.containerAccessConditions.modifiedAccessConditions) { + options.containerAccessConditions.modifiedAccessConditions = {}; + } + + if (!options.containerAccessConditions.leaseAccessConditions) { + options.containerAccessConditions.leaseAccessConditions = {}; + } + + if ( + options.containerAccessConditions.modifiedAccessConditions + .ifUnmodifiedSince || + (options.containerAccessConditions.modifiedAccessConditions.ifMatch && + options.containerAccessConditions.modifiedAccessConditions.ifMatch !== + ETagNone) || + (options.containerAccessConditions.modifiedAccessConditions.ifNoneMatch && + options.containerAccessConditions.modifiedAccessConditions + .ifNoneMatch !== ETagNone) + ) { + throw new RangeError( + "the IfUnmodifiedSince, IfMatch, and IfNoneMatch must have their default values\ + because they are ignored by the blob service" + ); + } + + return this.containerContext.setMetadata({ + abortSignal: aborter, + leaseAccessConditions: + options.containerAccessConditions.leaseAccessConditions, + metadata: options.metadata, + modifiedAccessConditions: + options.containerAccessConditions.modifiedAccessConditions + }); + } + + /** + * Gets the permissions for the specified container. The permissions indicate + * whether container data may be accessed publicly. + * + * WARNING: JavaScript Date will potential lost precision when parsing start and expiry string. + * For example, new Date("2018-12-31T03:44:23.8827891Z").toISOString() will get "2018-12-31T03:44:23.882Z". + * + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/get-container-acl + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IContainerGetAccessPolicyOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async getAccessPolicy( + aborter: Aborter, + options: IContainerGetAccessPolicyOptions = {} + ): Promise { + if (!options.leaseAccessConditions) { + options.leaseAccessConditions = {}; + } + + const response = await this.containerContext.getAccessPolicy({ + abortSignal: aborter, + leaseAccessConditions: options.leaseAccessConditions + }); + + const res: ContainerGetAccessPolicyResponse = { + _response: response._response, + blobPublicAccess: response.blobPublicAccess, + date: response.date, + eTag: response.eTag, + errorCode: response.errorCode, + lastModified: response.lastModified, + requestId: response.requestId, + signedIdentifiers: [], + version: response.version + }; + + for (const identifier of response) { + res.signedIdentifiers.push({ + accessPolicy: { + expiry: new Date(identifier.accessPolicy.expiry), + permission: identifier.accessPolicy.permission, + start: new Date(identifier.accessPolicy.start) + }, + id: identifier.id + }); + } + + return res; + } + + /** + * Sets the permissions for the specified container. The permissions indicate + * whether blobs in a container may be accessed publicly. + * + * When you set permissions for a container, the existing permissions are replaced. + * If no access or containerAcl provided, the existing container ACL will be + * removed. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-container-acl + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {PublicAccessType} [access] + * @param {ISignedIdentifier[]} [containerAcl] + * @param {IContainerSetAccessPolicyOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async setAccessPolicy( + aborter: Aborter, + access?: Models.PublicAccessType, + containerAcl?: ISignedIdentifier[], + options: IContainerSetAccessPolicyOptions = {} + ): Promise { + options.containerAccessConditions = options.containerAccessConditions || {}; + const acl: Models.SignedIdentifier[] = []; + for (const identifier of containerAcl || []) { + acl.push({ + accessPolicy: { + expiry: truncatedISO8061Date(identifier.accessPolicy.expiry), + permission: identifier.accessPolicy.permission, + start: truncatedISO8061Date(identifier.accessPolicy.start) + }, + id: identifier.id + }); + } + + return this.containerContext.setAccessPolicy({ + abortSignal: aborter, + access, + containerAcl: acl, + leaseAccessConditions: + options.containerAccessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.containerAccessConditions.modifiedAccessConditions + }); + } + + /** + * Establishes and manages a lock on a container for delete operations. + * The lock duration can be 15 to 60 seconds, or can be infinite. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-container + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} proposedLeaseId Can be specified in any valid GUID string format + * @param {number} duration Must be between 15 to 60 seconds, or infinite (-1) + * @param {IContainerAcquireLeaseOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async acquireLease( + aborter: Aborter, + proposedLeaseId: string, + duration: number, + options: IContainerAcquireLeaseOptions = {} + ): Promise { + return this.containerContext.acquireLease({ + abortSignal: aborter, + duration, + modifiedAccessConditions: options.modifiedAccessConditions, + proposedLeaseId + }); + } + + /** + * To free the lease if it is no longer needed so that another client may + * immediately acquire a lease against the container. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-container + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} leaseId + * @param {IContainerReleaseLeaseOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async releaseLease( + aborter: Aborter, + leaseId: string, + options: IContainerReleaseLeaseOptions = {} + ): Promise { + return this.containerContext.releaseLease(leaseId, { + abortSignal: aborter, + modifiedAccessConditions: options.modifiedAccessConditions + }); + } + + /** + * To renew an existing lease. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-container + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} leaseId + * @param {IContainerRenewLeaseOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async renewLease( + aborter: Aborter, + leaseId: string, + options: IContainerRenewLeaseOptions = {} + ): Promise { + return this.containerContext.renewLease(leaseId, { + abortSignal: aborter, + modifiedAccessConditions: options.modifiedAccessConditions + }); + } + + /** + * To end the lease but ensure that another client cannot acquire a new lease + * until the current lease period has expired. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-container + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {number} period break period + * @param {IContainerBreakLeaseOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async breakLease( + aborter: Aborter, + period: number, + options: IContainerBreakLeaseOptions = {} + ): Promise { + return this.containerContext.breakLease({ + abortSignal: aborter, + breakPeriod: period, + modifiedAccessConditions: options.modifiedAccessConditions + }); + } + + /** + * To change the ID of an existing lease. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/lease-container + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} leaseId + * @param {string} proposedLeaseId + * @param {IContainerChangeLeaseOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async changeLease( + aborter: Aborter, + leaseId: string, + proposedLeaseId: string, + options: IContainerChangeLeaseOptions = {} + ): Promise { + return this.containerContext.changeLease(leaseId, proposedLeaseId, { + abortSignal: aborter, + modifiedAccessConditions: options.modifiedAccessConditions + }); + } + + /** + * listBlobFlatSegment returns a single segment of blobs starting from the + * specified Marker. Use an empty Marker to start enumeration from the beginning. + * After getting a segment, process it, and then call ListBlobsFlatSegment again + * (passing the the previously-returned Marker) to get the next segment. + * @see https://docs.microsoft.com/rest/api/storageservices/list-blobs + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} [marker] + * @param {IContainerListBlobsSegmentOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async listBlobFlatSegment( + aborter: Aborter, + marker?: string, + options: IContainerListBlobsSegmentOptions = {} + ): Promise { + return this.containerContext.listBlobFlatSegment({ + abortSignal: aborter, + marker, + ...options + }); + } + + /** + * listBlobHierarchySegment returns a single segment of blobs starting from + * the specified Marker. Use an empty Marker to start enumeration from the + * beginning. After getting a segment, process it, and then call ListBlobsHierarchicalSegment + * again (passing the the previously-returned Marker) to get the next segment. + * @see https://docs.microsoft.com/rest/api/storageservices/list-blobs + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} delimiter + * @param {IContainerListBlobsSegmentOptions} [options] + * @returns {Promise} + * @memberof ContainerURL + */ + public async listBlobHierarchySegment( + aborter: Aborter, + delimiter: string, + marker?: string, + options: IContainerListBlobsSegmentOptions = {} + ): Promise { + return this.containerContext.listBlobHierarchySegment(delimiter, { + abortSignal: aborter, + marker, + ...options + }); + } +} diff --git a/file/lib/IAccountSASSignatureValues.ts b/file/lib/IAccountSASSignatureValues.ts new file mode 100644 index 0000000..e936716 --- /dev/null +++ b/file/lib/IAccountSASSignatureValues.ts @@ -0,0 +1,159 @@ +import { AccountSASPermissions } from "./AccountSASPermissions"; +import { AccountSASResourceTypes } from "./AccountSASResourceTypes"; +import { AccountSASServices } from "./AccountSASServices"; +import { SharedKeyCredential } from "./credentials/SharedKeyCredential"; +import { IIPRange, ipRangeToString } from "./IIPRange"; +import { SASProtocol, SASQueryParameters } from "./SASQueryParameters"; +import { SERVICE_VERSION } from "./utils/constants"; +import { truncatedISO8061Date } from "./utils/utils.common"; + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * IAccountSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage account. Once + * all the values here are set appropriately, call generateSASQueryParameters() to obtain a representation of the SAS + * which can actually be applied to blob urls. Note: that both this class and {@link SASQueryParameters} exist because + * the former is mutable and a logical representation while the latter is immutable and used to generate actual REST + * requests. + * + * @see https://docs.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1 + * for more conceptual information on SAS + * + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas + * for descriptions of the parameters, including which are required + * + * @export + * @class IAccountSASSignatureValues + */ +export interface IAccountSASSignatureValues { + /** + * If not provided, this defaults to the service version targeted by this version of the library. + * + * @type {string} + * @memberof IAccountSASSignatureValues + */ + version?: string; + + /** + * Optional. SAS protocols allowed. + * + * @type {SASProtocol} + * @memberof IAccountSASSignatureValues + */ + protocol?: SASProtocol; + + /** + * Optional. When the SAS will take effect. + * + * @type {Date} + * @memberof IAccountSASSignatureValues + */ + startTime?: Date; + + /** + * The time after which the SAS will no longer work. + * + * @type {Date} + * @memberof IAccountSASSignatureValues + */ + expiryTime: Date; + + /** + * Specifies which operations the SAS user may perform. Please refer to {@link AccountSASPermissions} for help + * constructing the permissions string. + * + * @type {string} + * @memberof IAccountSASSignatureValues + */ + permissions: string; + + /** + * Optional. IP range allowed. + * + * @type {IIPRange} + * @memberof IAccountSASSignatureValues + */ + ipRange?: IIPRange; + + /** + * The values that indicate the services accessible with this SAS. Please refer to {@link AccountSASService} to + * construct this value. + * + * @type {string} + * @memberof IAccountSASSignatureValues + */ + services: string; + + /** + * The values that indicate the resource types accessible with this SAS. Please refer + * to {@link AccountSASResourceType} to construct this value. + * + * @type {string} + * @memberof IAccountSASSignatureValues + */ + resourceTypes: string; +} + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * Generates a {@link SASQueryParameters} object which contains all SAS query parameters needed to make an actual + * REST request. + * + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas + * + * @param {SharedKeyCredential} sharedKeyCredential + * @returns {SASQueryParameters} + * @memberof IAccountSASSignatureValues + */ +export function generateAccountSASQueryParameters( + accountSASSignatureValues: IAccountSASSignatureValues, + sharedKeyCredential: SharedKeyCredential +): SASQueryParameters { + const version = accountSASSignatureValues.version + ? accountSASSignatureValues.version + : SERVICE_VERSION; + + const parsedPermissions = AccountSASPermissions.parse( + accountSASSignatureValues.permissions + ).toString(); + const parsedServices = AccountSASServices.parse( + accountSASSignatureValues.services + ).toString(); + const parsedResourceTypes = AccountSASResourceTypes.parse( + accountSASSignatureValues.resourceTypes + ).toString(); + + const stringToSign = [ + sharedKeyCredential.accountName, + parsedPermissions, + parsedServices, + parsedResourceTypes, + accountSASSignatureValues.startTime + ? truncatedISO8061Date(accountSASSignatureValues.startTime) + : "", + truncatedISO8061Date(accountSASSignatureValues.expiryTime), + accountSASSignatureValues.ipRange + ? ipRangeToString(accountSASSignatureValues.ipRange) + : "", + accountSASSignatureValues.protocol + ? accountSASSignatureValues.protocol + : "", + version, + "" // Account SAS requires an additional newline character + ].join("\n"); + + const signature: string = sharedKeyCredential.computeHMACSHA256(stringToSign); + + return new SASQueryParameters( + version, + parsedPermissions, + signature, + parsedServices, + parsedResourceTypes, + accountSASSignatureValues.protocol, + accountSASSignatureValues.startTime, + accountSASSignatureValues.expiryTime, + accountSASSignatureValues.ipRange + ); +} diff --git a/file/lib/IBlobSASSignatureValues.ts b/file/lib/IBlobSASSignatureValues.ts new file mode 100644 index 0000000..f414fbc --- /dev/null +++ b/file/lib/IBlobSASSignatureValues.ts @@ -0,0 +1,251 @@ +import { BlobSASPermissions } from "./BlobSASPermissions"; +import { ContainerSASPermissions } from "./ContainerSASPermissions"; +import { SharedKeyCredential } from "./credentials/SharedKeyCredential"; +import { IIPRange, ipRangeToString } from "./IIPRange"; +import { SASProtocol } from "./SASQueryParameters"; +import { SASQueryParameters } from "./SASQueryParameters"; +import { SERVICE_VERSION } from "./utils/constants"; +import { truncatedISO8061Date } from "./utils/utils.common"; + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * IBlobSASSignatureValues is used to help generating Blob service SAS tokens for containers or blobs. + * + * @export + * @class IBlobSASSignatureValues + */ +export interface IBlobSASSignatureValues { + /** + * The version of the service this SAS will target. If not specified, it will default to the version targeted by the + * library. + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + version?: string; + + /** + * Optional. SAS protocols, HTTPS only or HTTPSandHTTP + * + * @type {SASProtocol} + * @memberof IBlobSASSignatureValues + */ + protocol?: SASProtocol; + + /** + * Optional. When the SAS will take effect. + * + * @type {Date} + * @memberof IBlobSASSignatureValues + */ + startTime?: Date; + + /** + * Optional only when identifier is provided. The time after which the SAS will no longer work. + * + * @type {Date} + * @memberof IBlobSASSignatureValues + */ + expiryTime?: Date; + + /** + * Optional only when identifier is provided. + * Please refer to either {@link ContainerSASPermissions} or {@link BlobSASPermissions} depending on the resource + * being accessed for help constructing the permissions string. + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + permissions?: string; + + /** + * Optional. IP ranges allowed in this SAS. + * + * @type {IIPRange} + * @memberof IBlobSASSignatureValues + */ + ipRange?: IIPRange; + + /** + * The name of the container the SAS user may access. + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + containerName: string; + + /** + * Optional. The name of the container the SAS user may access. + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + blobName?: string; + + /** + * Optional. The name of the access policy on the container this SAS references if any. + * + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/establishing-a-stored-access-policy + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + identifier?: string; + + /** + * Optional. The cache-control header for the SAS. + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + cacheControl?: string; + + /** + * Optional. The content-disposition header for the SAS. + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + contentDisposition?: string; + + /** + * Optional. The content-encoding header for the SAS. + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + contentEncoding?: string; + + /** + * Optional. The content-language header for the SAS. + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + contentLanguage?: string; + + /** + * Optional. The content-type header for the SAS. + * + * @type {string} + * @memberof IBlobSASSignatureValues + */ + contentType?: string; +} + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * 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, startTime and identifier. + * + * WARNING: When identifier is not provided, permissions and expiryTime are required. + * You MUST assign value to identifier or expiryTime & permissions manually if you initial with + * this constructor. + * + * @export + * @param {IBlobSASSignatureValues} blobSASSignatureValues + * @param {SharedKeyCredential} sharedKeyCredential + * @returns {SASQueryParameters} + */ +export function generateBlobSASQueryParameters( + blobSASSignatureValues: IBlobSASSignatureValues, + sharedKeyCredential: SharedKeyCredential +): SASQueryParameters { + if ( + !blobSASSignatureValues.identifier && + (!blobSASSignatureValues.permissions && !blobSASSignatureValues.expiryTime) + ) { + throw new RangeError( + "Must provide 'permissions' and 'expiryTime' for Blob SAS generation when 'identifier' is not provided." + ); + } + + const version = blobSASSignatureValues.version + ? blobSASSignatureValues.version + : SERVICE_VERSION; + let resource: string = "c"; + let verifiedPermissions: string | undefined; + + // Calling parse and toString guarantees the proper ordering and throws on invalid characters. + if (blobSASSignatureValues.permissions) { + if (blobSASSignatureValues.blobName) { + verifiedPermissions = BlobSASPermissions.parse( + blobSASSignatureValues.permissions + ).toString(); + resource = "b"; + } else { + verifiedPermissions = ContainerSASPermissions.parse( + blobSASSignatureValues.permissions + ).toString(); + } + } + + // Signature is generated on the un-url-encoded values. + const stringToSign = [ + verifiedPermissions ? verifiedPermissions : "", + blobSASSignatureValues.startTime + ? truncatedISO8061Date(blobSASSignatureValues.startTime) + : "", + blobSASSignatureValues.expiryTime + ? truncatedISO8061Date(blobSASSignatureValues.expiryTime) + : "", + getCanonicalName( + sharedKeyCredential.accountName, + blobSASSignatureValues.containerName, + blobSASSignatureValues.blobName + ), + blobSASSignatureValues.identifier, + blobSASSignatureValues.ipRange + ? ipRangeToString(blobSASSignatureValues.ipRange) + : "", + blobSASSignatureValues.protocol ? blobSASSignatureValues.protocol : "", + 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 new SASQueryParameters( + version, + signature, + verifiedPermissions, + undefined, + undefined, + blobSASSignatureValues.protocol, + blobSASSignatureValues.startTime, + blobSASSignatureValues.expiryTime, + blobSASSignatureValues.ipRange, + blobSASSignatureValues.identifier, + resource + ); +} + +function getCanonicalName( + accountName: string, + containerName: string, + blobName?: string +): string { + // Container: "/blob/account/containerName" + // Blob: "/blob/account/containerName/blobName" + const elements: string[] = [`/blob/${accountName}/${containerName}`]; + if (blobName) { + elements.push(`/${blobName}`); + } + return elements.join(""); +} diff --git a/file/lib/IIPRange.ts b/file/lib/IIPRange.ts new file mode 100644 index 0000000..aa15037 --- /dev/null +++ b/file/lib/IIPRange.ts @@ -0,0 +1,37 @@ +/** + * Allowed IP range for a SAS. + * + * @export + * @interface IIPRange + */ +export interface IIPRange { + /** + * Starting IP address in the IP range. + * If end IP doesn't provide, start IP will the only IP allowed. + * + * @type {string} + * @memberof IPRange + */ + start: string; + /** + * Optional. IP address that ends the IP range. + * If not provided, start IP will the only IP allowed. + * + * @type {string} + * @memberof IPRange + */ + end?: string; +} + +/** + * Generate IPRange format string. For example: + * + * "8.8.8.8" or "1.1.1.1-255.255.255.255" + * + * @export + * @param {IIPRange} ipRange + * @returns {string} + */ +export function ipRangeToString(ipRange: IIPRange): string { + return ipRange.end ? `${ipRange.start}-${ipRange.end}` : ipRange.start; +} diff --git a/file/lib/IRange.ts b/file/lib/IRange.ts new file mode 100644 index 0000000..1615bbf --- /dev/null +++ b/file/lib/IRange.ts @@ -0,0 +1,48 @@ +// tslint:disable:max-line-length +/** + * Range for Blob Service Operations. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-the-range-header-for-blob-service-operations + * + * @export + * @interface IRange + */ +export interface IRange { + /** + * StartByte, larger than or equal 0. + * + * @type {string} + * @memberof IRange + */ + offset: number; + /** + * Optional. Count of bytes, larger than 0. + * If not provided, will return bytes from offset to the end. + * + * @type {string} + * @memberof IRange + */ + count?: number; +} + +/** + * Generate a range string. For example: + * + * "bytes=255-" or "bytes=0-511" + * + * @export + * @param {IRange} iRange + * @returns {string} + */ +export function rangeToString(iRange: IRange): string { + if (iRange.offset < 0) { + throw new RangeError(`IRange.offset cannot be smaller than 0.`); + } + if (iRange.count && iRange.count <= 0) { + throw new RangeError( + `IRange.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}-`; +} diff --git a/file/lib/LoggingPolicyFactory.ts b/file/lib/LoggingPolicyFactory.ts new file mode 100644 index 0000000..7120bb8 --- /dev/null +++ b/file/lib/LoggingPolicyFactory.ts @@ -0,0 +1,45 @@ +import { + RequestPolicy, + RequestPolicyFactory, + RequestPolicyOptions +} from "ms-rest-js"; + +import { LoggingPolicy } from "./policies/LoggingPolicy"; + +/** + * RequestLogOptions configures the retry policy's behavior. + * + * @export + * @interface IRequestLogOptions + */ +export interface IRequestLogOptions { + /** + * LogWarningIfTryOverThreshold logs a warning if a tried operation takes longer than the specified + * duration in ms. Default is 3000ms. + * @type {number} + * @memberof IRequestLogOptions + */ + logWarningIfTryOverThreshold: number; +} + +/** + * LoggingPolicyFactory is a factory class helping generating LoggingPolicy objects. + * + * @export + * @class LoggingPolicyFactory + * @implements {RequestPolicyFactory} + */ +export class LoggingPolicyFactory implements RequestPolicyFactory { + private readonly loggingOptions?: IRequestLogOptions; + + constructor(loggingOptions?: IRequestLogOptions) { + this.loggingOptions = loggingOptions; + } + + public create( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions + ): LoggingPolicy { + return new LoggingPolicy(nextPolicy, options, this.loggingOptions); + } +} diff --git a/file/lib/PageBlobURL.ts b/file/lib/PageBlobURL.ts new file mode 100644 index 0000000..e2a4b29 --- /dev/null +++ b/file/lib/PageBlobURL.ts @@ -0,0 +1,382 @@ +import { HttpRequestBody, TransferProgressEvent } from "ms-rest-js"; + +import * as Models from "../lib/generated/models"; +import { Aborter } from "./Aborter"; +import { BlobURL } from "./BlobURL"; +import { ContainerURL } from "./ContainerURL"; +import { PageBlob } from "./generated/operations"; +import { rangeToString } from "./IRange"; +import { + IBlobAccessConditions, + IMetadata, + IPageBlobAccessConditions +} from "./models"; +import { Pipeline } from "./Pipeline"; +import { URLConstants } from "./utils/constants"; +import { appendToURLPath, setURLParameter } from "./utils/utils.common"; + +export interface IPageBlobCreateOptions { + accessConditions?: IBlobAccessConditions; + blobSequenceNumber?: number; + blobHTTPHeaders?: Models.BlobHTTPHeaders; + metadata?: IMetadata; +} + +export interface IPageBlobUploadPagesOptions { + accessConditions?: IPageBlobAccessConditions; + progress?: (progress: TransferProgressEvent) => void; + transactionalContentMD5?: Uint8Array; +} + +export interface IPageBlobClearPagesOptions { + accessConditions?: IPageBlobAccessConditions; +} + +export interface IPageBlobGetPageRangesOptions { + accessConditions?: IBlobAccessConditions; +} + +export interface IPageBlobGetPageRangesDiffOptions { + accessConditions?: IBlobAccessConditions; + range?: string; +} + +export interface IPageBlobResizeOptions { + accessConditions?: IBlobAccessConditions; +} + +export interface IPageBlobUpdateSequenceNumberOptions { + accessConditions?: IBlobAccessConditions; +} + +export interface IPageBlobStartCopyIncrementalOptions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; +} + +/** + * PageBlobURL defines a set of operations applicable to page blobs. + * + * @export + * @class PageBlobURL + * @extends {StorageURL} + */ +export class PageBlobURL extends BlobURL { + /** + * Creates a PageBlobURL object from ContainerURL instance. + * + * @static + * @param {ContainerURL} containerURL + * @param {string} blobName + * @returns {PageBlobURL} + * @memberof PageBlobURL + */ + public static fromContainerURL( + containerURL: ContainerURL, + blobName: string + ): PageBlobURL { + return new PageBlobURL( + appendToURLPath(containerURL.url, blobName), + containerURL.pipeline + ); + } + + /** + * Creates a PageBlobURL object from BlobURL instance. + * + * @static + * @param {BlobURL} blobURL + * @returns {PageBlobURL} + * @memberof PageBlobURL + */ + public static fromBlobURL(blobURL: BlobURL): PageBlobURL { + return new PageBlobURL(blobURL.url, blobURL.pipeline); + } + + /** + * pageBlobsContext provided by protocol layer. + * + * @private + * @type {PageBlobs} + * @memberof PageBlobURL + */ + private pageBlobContext: PageBlob; + + /** + * Creates an instance of PageBlobURL. + * @param {string} url A URL string pointing to Azure Storage page blob, such as + * "https://myaccount.blob.core.windows.net/mycontainer/pageblob". You can + * append a SAS if using AnonymousCredential, such as + * "https://myaccount.blob.core.windows.net/mycontainer/pageblob?sasString". + * @param {Pipeline} pipeline Call StorageURL.newPipeline() to create a default + * pipeline, or provide a customized pipeline. + * @memberof PageBlobURL + */ + constructor(url: string, pipeline: Pipeline) { + super(url, pipeline); + this.pageBlobContext = new PageBlob(this.storageClientContext); + } + + /** + * Creates a new PageBlobURL object identical to the source but with the + * specified request policy pipeline. + * + * @param {Pipeline} pipeline + * @returns {PageBlobURL} + * @memberof PageBlobURL + */ + public withPipeline(pipeline: Pipeline): PageBlobURL { + return new PageBlobURL(this.url, pipeline); + } + + /** + * Creates a new PageBlobURL 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 {string} snapshot + * @returns {PageBlobURL} + * @memberof PageBlobURL + */ + public withSnapshot(snapshot: string): PageBlobURL { + return new PageBlobURL( + setURLParameter( + this.url, + URLConstants.Parameters.SNAPSHOT, + snapshot.length === 0 ? undefined : snapshot + ), + this.pipeline + ); + } + + /** + * Creates a page blob of the specified length. Call uploadPages to upload data + * data to a page blob. + * @see https://docs.microsoft.com/rest/api/storageservices/put-blob + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {number} size + * @param {IPageBlobCreateOptions} [options] + * @returns {Promise} + * @memberof PageBlobURL + */ + public async create( + aborter: Aborter, + size: number, + options: IPageBlobCreateOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.pageBlobContext.create(0, size, { + abortSignal: aborter, + blobHTTPHeaders: options.blobHTTPHeaders, + blobSequenceNumber: options.blobSequenceNumber, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + metadata: options.metadata, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions + }); + } + + /** + * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. + * @see https://docs.microsoft.com/rest/api/storageservices/put-page + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {HttpRequestBody} body + * @param {number} offset Offset of destination page blob + * @param {number} count Content length of body, also how many bytes to be uploaded + * @param {IPageBlobUploadPagesOptions} [options] + * @returns {Promise} + * @memberof PageBlobURL + */ + public async uploadPages( + aborter: Aborter, + body: HttpRequestBody, + offset: number, + count: number, + options: IPageBlobUploadPagesOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.pageBlobContext.uploadPages(body, count, { + abortSignal: aborter, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions, + onUploadProgress: options.progress, + range: rangeToString({ offset, count }), + sequenceNumberAccessConditions: + options.accessConditions.sequenceNumberAccessConditions, + transactionalContentMD5: options.transactionalContentMD5 + }); + } + + /** + * Frees the specified pages from the page blob. + * @see https://docs.microsoft.com/rest/api/storageservices/put-page + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {number} offset + * @param {number} count + * @param {IPageBlobClearPagesOptions} [options] + * @returns {Promise} + * @memberof PageBlobURL + */ + public async clearPages( + aborter: Aborter, + offset: number, + count: number, + options: IPageBlobClearPagesOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.pageBlobContext.clearPages(0, { + abortSignal: aborter, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions, + range: rangeToString({ offset, count }), + sequenceNumberAccessConditions: + options.accessConditions.sequenceNumberAccessConditions + }); + } + + /** + * Returns the list of valid page ranges for a page blob or snapshot of a page blob. + * @see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {number} offset + * @param {number} count + * @param {IPageBlobGetPageRangesOptions} [options] + * @returns {Promise} + * @memberof PageBlobURL + */ + public async getPageRanges( + aborter: Aborter, + offset: number, + count: number, + options: IPageBlobGetPageRangesOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.pageBlobContext.getPageRanges({ + abortSignal: aborter, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions, + range: rangeToString({ offset, count }) + }); + } + + /** + * Gets the collection of page ranges that differ between a specified snapshot and this page blob. + * @see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {number} offset + * @param {number} count + * @param {string} prevSnapshot + * @param {IPageBlobGetPageRangesDiffOptions} [options] + * @returns {Promise} + * @memberof PageBlobURL + */ + public async getPageRangesDiff( + aborter: Aborter, + offset: number, + count: number, + prevSnapshot: string, + options: IPageBlobGetPageRangesDiffOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.pageBlobContext.getPageRangesDiff({ + abortSignal: aborter, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions, + prevsnapshot: prevSnapshot, + range: rangeToString({ offset, count }) + }); + } + + /** + * Resizes the page blob to the specified size (which must be a multiple of 512). + * @see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {number} size + * @param {IPageBlobResizeOptions} [options] + * @returns {Promise} + * @memberof PageBlobURL + */ + public async resize( + aborter: Aborter, + size: number, + options: IPageBlobResizeOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.pageBlobContext.resize(size, { + abortSignal: aborter, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions + }); + } + + /** + * Sets a page blob's sequence number. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-properties + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {Models.SequenceNumberActionType} sequenceNumberAction + * @param {number} [sequenceNumber] Required if sequenceNumberAction is max or update + * @param {IPageBlobUpdateSequenceNumberOptions} [options] + * @returns {Promise} + * @memberof PageBlobURL + */ + public async updateSequenceNumber( + aborter: Aborter, + sequenceNumberAction: Models.SequenceNumberActionType, + sequenceNumber?: number, + options: IPageBlobUpdateSequenceNumberOptions = {} + ): Promise { + options.accessConditions = options.accessConditions || {}; + return this.pageBlobContext.updateSequenceNumber(sequenceNumberAction, { + abortSignal: aborter, + blobSequenceNumber: sequenceNumber, + leaseAccessConditions: options.accessConditions.leaseAccessConditions, + modifiedAccessConditions: + options.accessConditions.modifiedAccessConditions + }); + } + + /** + * 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://docs.microsoft.com/rest/api/storageservices/incremental-copy-blob + * @see https://docs.microsoft.com/en-us/azure/virtual-machines/windows/incremental-snapshots + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} copySource Specifies the name of the source page blob snapshot. For example, + * https://myaccount.blob.core.windows.net/mycontainer/myblob?snapshot= + * @param {IPageBlobStartCopyIncrementalOptions} [options] + * @returns {Promise} + * @memberof PageBlobURL + */ + public async startCopyIncremental( + aborter: Aborter, + copySource: string, + options: IPageBlobStartCopyIncrementalOptions = {} + ): Promise { + return this.pageBlobContext.copyIncremental(copySource, { + abortSignal: aborter, + modifiedAccessConditions: options.modifiedAccessConditions + }); + } +} diff --git a/file/lib/Pipeline.ts b/file/lib/Pipeline.ts new file mode 100644 index 0000000..69b78a0 --- /dev/null +++ b/file/lib/Pipeline.ts @@ -0,0 +1,84 @@ +import { + BaseRequestPolicy, + HttpClient as IHttpClient, + HttpHeaders, + HttpOperationResponse, + HttpPipelineLogger as IHttpPipelineLogger, + HttpPipelineLogLevel, + RequestPolicy, + RequestPolicyFactory, + RequestPolicyOptions, + ServiceClientOptions, + WebResource +} from "ms-rest-js"; + +// Export following interfaces and types for customers who want to implement their +// own RequestPolicy or HTTPClient +export { + IHttpClient, + IHttpPipelineLogger, + HttpHeaders, + HttpPipelineLogLevel, + HttpOperationResponse, + WebResource, + BaseRequestPolicy, + RequestPolicyFactory, + RequestPolicy, + RequestPolicyOptions +}; + +/** + * Option interface for Pipeline constructor. + * + * @export + * @interface IPipelineOptions + */ +export interface IPipelineOptions { + logger?: IHttpPipelineLogger; + HTTPClient?: IHttpClient; +} + +/** + * A Pipeline class containing HTTP request policies. + * You can create a default Pipeline by calling StorageURL.newPipeline(). + * Or you can create a Pipeline with your own policies by the constructor of Pipeline. + * Refer to StorageURL.newPipeline() and provided policies as reference before + * implementing your customized Pipeline. + * + * @export + * @class Pipeline + */ +export class Pipeline { + public readonly factories: RequestPolicyFactory[]; + public readonly options: IPipelineOptions; + + /** + * Creates an instance of Pipeline. Customize HTTPClient by implementing IHttpClient interface. + * + * @param {RequestPolicyFactory[]} factories + * @param {IPipelineOptions} [options={}] + * @memberof Pipeline + */ + constructor( + factories: RequestPolicyFactory[], + options: IPipelineOptions = {} + ) { + this.factories = factories; + this.options = options; + } + + /** + * Transfer Pipeline object to ServiceClientOptions object which required by + * ServiceClient constructor. + * + * @returns {ServiceClientOptions} + * @memberof Pipeline + */ + public toServiceClientOptions(): ServiceClientOptions { + return { + httpClient: this.options.HTTPClient, + httpPipelineLogger: this.options.logger, + requestPolicyFactories: this.factories + }; + } +} diff --git a/file/lib/RetryPolicyFactory.ts b/file/lib/RetryPolicyFactory.ts new file mode 100644 index 0000000..ed96359 --- /dev/null +++ b/file/lib/RetryPolicyFactory.ts @@ -0,0 +1,106 @@ +import { + RequestPolicy, + RequestPolicyFactory, + RequestPolicyOptions +} from "ms-rest-js"; + +import { RetryPolicy, RetryPolicyType } from "./policies/RetryPolicy"; + +/** + * Retry options interface. + * + * @export + * @interface IRetryOptions + */ +export interface IRetryOptions { + /** + * Optional. RetryPolicyType, default is exponential retry policy. + * + * @type {RetryPolicyType} + * @memberof RetryOptions + */ + readonly retryPolicyType?: RetryPolicyType; + + /** + * Optional. Max try number of attempts, default is 4. + * A value of 1 means 1 try and no retries. + * A value smaller than 1 means default retry number of attempts. + * + * @type {number} + * @memberof IRetryOptions + */ + readonly maxTries?: number; + + /** + * Optional. Indicates the maximum time in seconds allowed for any single try of an HTTP request. + * A value of zero or undefined means that you accept our default timeout, 60s or 60 * 1000ms. + * + * NOTE: When transferring large amounts of data, the default TryTimeout will probably + * not be sufficient. You should override this value based on the bandwidth available to + * the host machine and proximity to the Storage service. A good starting point may be something + * like (60 seconds per MB of anticipated-payload-size) + * + * @type {number} + * @memberof IRetryOptions + */ + readonly tryTimeout?: number; + + /** + * Optional. Specifies the amount of delay to use before retrying an operation (default is 4s or 4 * 1000ms). + * The delay increases (exponentially or linearly) with each retry up to a maximum specified by + * maxRetryDelayInMs. If you specify 0, then you must also specify 0 for maxRetryDelayInMs. + * + * @type {number} + * @memberof IRetryOptions + */ + readonly retryDelayInMs?: number; + + /** + * Optional. Specifies the maximum delay allowed before retrying an operation (default is 120s or 120 * 1000ms). + * If you specify 0, then you must also specify 0 for retryDelayInMs. + * + * @type {number} + * @memberof IRetryOptions + */ + readonly maxRetryDelayInMs?: number; + + /** + * If a secondaryHost is specified, retries will be tried against this host. If secondaryHost is undefined + * (the default) then operations are not retried against another host. + * + * NOTE: Before setting this field, make sure you understand the issues around + * reading stale and potentially-inconsistent data at + * {@link https://docs.microsoft.com/en-us/azure/storage/common/storage-designing-ha-apps-with-ragrs} + * + * @type {string} + * @memberof IRetryOptions + */ + readonly secondaryHost?: string; +} + +/** + * RetryPolicyFactory is a factory class helping generating RetryPolicy objects. + * + * @export + * @class RetryPolicyFactory + * @implements {RequestPolicyFactory} + */ +export class RetryPolicyFactory implements RequestPolicyFactory { + private retryOptions?: IRetryOptions; + + /** + * Creates an instance of RetryPolicyFactory. + * @param {IRetryOptions} [retryOptions] + * @memberof RetryPolicyFactory + */ + constructor(retryOptions?: IRetryOptions) { + this.retryOptions = retryOptions; + } + + public create( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions + ): RetryPolicy { + return new RetryPolicy(nextPolicy, options, this.retryOptions); + } +} diff --git a/file/lib/SASQueryParameters.ts b/file/lib/SASQueryParameters.ts new file mode 100644 index 0000000..7b7744b --- /dev/null +++ b/file/lib/SASQueryParameters.ts @@ -0,0 +1,288 @@ +import { IIPRange, ipRangeToString } from "./IIPRange"; +import { truncatedISO8061Date } from "./utils/utils.common"; + +/** + * Protocols for generated SAS. + * + * @export + * @enum {number} + */ +export enum SASProtocol { + /** + * Protocol that allows HTTPS only + */ + HTTPS = "https", + + /** + * Protocol that allows both HTTPS and HTTP + */ + HTTPSandHTTP = "https,http" +} + +/** + * 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 ServiceSASSignatureValues} + * types. Once generated, it can be encoded into a {@code 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. + * + * @export + * @class SASQueryParameters + */ +export class SASQueryParameters { + /** + * The storage API version. + * + * @type {string} + * @memberof SASQueryParameters + */ + public readonly version: string; + + /** + * Optional. The allowed HTTP protocol(s). + * + * @type {SASProtocol} + * @memberof SASQueryParameters + */ + public readonly protocol?: SASProtocol; + + /** + * Optional. The start time for this SAS token. + * + * @type {Date} + * @memberof SASQueryParameters + */ + public readonly startTime?: Date; + + /** + * Optional only when identifier is provided. The expiry time for this SAS token. + * + * @type {Date} + * @memberof SASQueryParameters + */ + public readonly expiryTime?: Date; + + /** + * Optional only when identifier is provided. + * Please refer to {@link AccountSASPermission}, {@link BlobSASPermission}, or {@link ContainerSASPermission} for + * more details. + * + * @type {string} + * @memberof SASQueryParameters + */ + public readonly permissions?: string; + + /** + * Optional. The storage services being accessed (only for Account SAS). Please refer to {@link AccountSASServices} + * for more details. + * + * @type {string} + * @memberof SASQueryParameters + */ + public readonly services?: string; + + /** + * Optional. The storage resource types being accessed (only for Account SAS). Please refer to + * {@link AccountSASResourceTypes} for more details. + * + * @type {string} + * @memberof SASQueryParameters + */ + public readonly resourceTypes?: string; + + /** + * Optional. The signed identifier (only for {@link ServiceSASSignatureValues}). + * + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/establishing-a-stored-access-policy + * + * @type {string} + * @memberof SASQueryParameters + */ + public readonly identifier?: string; + + /** + * Optional. The storage container or blob (only for {@link ServiceSASSignatureValues}). + * + * @type {string} + * @memberof SASQueryParameters + */ + public readonly resource?: string; + + /** + * The signature for the SAS token. + * + * @type {string} + * @memberof SASQueryParameters + */ + public readonly signature: string; + + /** + * Inner value of getter ipRange. + * + * @private + * @type {IIPRange} + * @memberof SASQueryParameters + */ + private readonly ipRangeInner?: IIPRange; + + /** + * Optional. IP range allowed for this SAS. + * + * @readonly + * @type {(IIPRange | undefined)} + * @memberof SASQueryParameters + */ + public get ipRange(): IIPRange | undefined { + if (this.ipRangeInner) { + return { + end: this.ipRangeInner.end, + start: this.ipRangeInner.start + }; + } + return undefined; + } + + /** + * Creates an instance of SASQueryParameters. + * + * @param {string} version Representing the storage version + * @param {string} signature Representing the signature for the SAS token + * @param {string} [permissions] Representing the storage permissions + * @param {string} [services] Representing the storage services being accessed (only for Account SAS) + * @param {string} [resourceTypes] Representing the storage resource types being accessed (only for Account SAS) + * @param {SASProtocol} [protocol] Representing the allowed HTTP protocol(s) + * @param {Date} [startTime] Representing the start time for this SAS token + * @param {Date} [expiryTime] Representing the expiry time for this SAS token + * @param {IIPRange} [ipRange] Representing the range of valid IP addresses for this SAS token + * @param {string} [identifier] Representing the signed identifier (only for Service SAS) + * @param {string} [resource] Representing the storage container or blob (only for Service SAS) + * @memberof SASQueryParameters + */ + constructor( + version: string, + signature: string, + permissions?: string, + services?: string, + resourceTypes?: string, + protocol?: SASProtocol, + startTime?: Date, + expiryTime?: Date, + ipRange?: IIPRange, + identifier?: string, + resource?: string + ) { + this.version = version; + this.services = services; + this.resourceTypes = resourceTypes; + this.expiryTime = expiryTime; + this.permissions = permissions; + this.protocol = protocol; + this.startTime = startTime; + this.ipRangeInner = ipRange; + this.identifier = identifier; + this.resource = resource; + this.signature = signature; + } + + /** + * Encodes all SAS query parameters into a string that can be appended to a URL. + * + * @returns {string} + * @memberof SASQueryParameters + */ + public toString(): string { + const params: string[] = [ + "sv", + "ss", + "srt", + "spr", + "st", + "se", + "sip", + "si", + "sr", + "sp", + "sig" + ]; + const queries: string[] = []; + + 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.startTime ? truncatedISO8061Date(this.startTime) : undefined + ); + break; + case "se": + this.tryAppendQueryParameter( + queries, + param, + this.expiryTime ? truncatedISO8061Date(this.expiryTime) : 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 "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; + } + } + return queries.join("&"); + } + + /** + * A private helper method used to filter and append query key/value pairs into an array. + * + * @private + * @param {string[]} queries + * @param {string} key + * @param {string} [value] + * @returns {void} + * @memberof SASQueryParameters + */ + private tryAppendQueryParameter( + queries: string[], + key: string, + value?: string + ): void { + if (!value) { + return; + } + + key = encodeURIComponent(key); + value = encodeURIComponent(value); + if (key.length > 0 && value.length > 0) { + queries.push(`${key}=${value}`); + } + } +} diff --git a/file/lib/ServiceURL.ts b/file/lib/ServiceURL.ts new file mode 100644 index 0000000..0e2f8b3 --- /dev/null +++ b/file/lib/ServiceURL.ts @@ -0,0 +1,147 @@ +import * as Models from "../lib/generated/models"; +import { Aborter } from "./Aborter"; +import { Service } from "./generated/operations"; +import { Pipeline } from "./Pipeline"; +import { StorageURL } from "./StorageURL"; + +export interface IServiceListSharesSegmentOptions { + /** + * Filters the results to return only entries whose + * name begins with the specified prefix. + * + * @type {string} + * @memberof IServiceListSharesSegmentOptions + */ + prefix?: string; + + /** + * Specifies the maximum number of entries to + * return. If the request does not specify maxresults, or specifies a value + * greater than 5,000, the server will return up to 5,000 items. + * + * @type {number} + * @memberof IServiceListSharesSegmentOptions + */ + maxresults?: number; + + /** + * Include this parameter to + * specify one or more datasets to include in the response. + * + * @type {Models.ListSharesIncludeType[]} + * @memberof IServiceListSharesSegmentOptions + */ + include?: Models.ListSharesIncludeType[]; +} + +/** + * A ServiceURL represents a URL to the Azure Storage File service allowing you + * to manipulate file shares. + * + * @export + * @class ServiceURL + * @extends {StorageURL} + */ +export class ServiceURL extends StorageURL { + /** + * serviceContext provided by protocol layer. + * + * @private + * @type {Service} + * @memberof ServiceURL + */ + private serviceContext: Service; + + /** + * Creates an instance of ServiceURL. + * + * @param {string} url A URL string pointing to Azure Storage file service, such as + * "https://myaccount.file.core.windows.net". You can Append a SAS + * if using AnonymousCredential, such as "https://myaccount.file.core.windows.net?sasString". + * @param {Pipeline} pipeline Call StorageURL.newPipeline() to create a default + * pipeline, or provide a customized pipeline. + * @memberof ServiceURL + */ + constructor(url: string, pipeline: Pipeline) { + super(url, pipeline); + this.serviceContext = new Service(this.storageClientContext); + } + + /** + * Creates a new ServiceURL object identical to the source but with the + * specified request policy pipeline. + * + * @param {Pipeline} pipeline + * @returns {ServiceURL} + * @memberof ServiceURL + */ + public withPipeline(pipeline: Pipeline): ServiceURL { + return new ServiceURL(this.url, pipeline); + } + + /** + * Gets the properties of a storage account’s file service, including properties + * for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/get-file-service-properties} + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @returns {Promise} + * @memberof ServiceURL + */ + public async getProperties( + aborter: Aborter + ): Promise { + return this.serviceContext.getProperties({ + abortSignal: aborter + }); + } + + /** + * Sets properties for a storage account’s file service endpoint, including properties + * for Storage Analytics, CORS (Cross-Origin Resource Sharing) rules and soft delete settings. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-file-service-properties} + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {Models.StorageServiceProperties} properties + * @returns {Promise} + * @memberof ServiceURL + */ + public async setProperties( + aborter: Aborter, + properties: Models.StorageServiceProperties + ): Promise { + return this.serviceContext.setProperties(properties, { + abortSignal: aborter + }); + } + + /** + * Gets the properties of a storage account's File service, including properties for Storage + * Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} [marker] A string value that identifies the portion of + * the list to be returned with the next list operation. The operation + * returns a marker value within the response body if the list returned was + * not complete. The marker value may then be used in a subsequent call to + * request the next set of list items. The marker value is opaque to the + * client. + * @param {IServiceListSharesSegmentOptions} [options={}] + * @returns {Promise} + * @memberof ServiceURL + */ + public async listSharesSegment( + aborter: Aborter, + marker?: string, + options: IServiceListSharesSegmentOptions = {} + ): Promise { + return this.serviceContext.listSharesSegment({ + abortSignal: aborter, + marker, + ...options + }); + } +} diff --git a/file/lib/ShareURL.ts b/file/lib/ShareURL.ts new file mode 100644 index 0000000..8363020 --- /dev/null +++ b/file/lib/ShareURL.ts @@ -0,0 +1,440 @@ +import { HttpResponse } from "ms-rest-js"; +import { Aborter } from "./Aborter"; +import * as Models from "./generated/models"; +import { Share } from "./generated/operations"; +import { Pipeline } from "./Pipeline"; +import { ServiceURL } from "./ServiceURL"; +import { StorageURL } from "./StorageURL"; +import { ETagNone, URLConstants } from "./utils/constants"; +import { + appendToURLPath, + setURLParameter, + truncatedISO8061Date +} from "./utils/utils.common"; + +export interface IShareCreateOptions { + /** + * A name-value pair to associate with a file storage object. + * + * @type {{ [propertyName: string]: string }} + * @memberof IShareCreateOptions + */ + metadata?: { [propertyName: string]: string }; + + /** + * Specifies the maximum size of the share, in + * gigabytes. + * + * @type {number} + * @memberof IShareCreateOptions + */ + quota?: number; +} + +export interface IShareGetPropertiesOptions { + /** + * The snapshot parameter is an opaque + * DateTime value that, when present, specifies the share snapshot to query. + * + * @type {string} + * @memberof IShareGetPropertiesOptions + */ + sharesnapshot?: string; +} + +export interface IShareDeleteMethodOptions { + /** + * The snapshot parameter is an opaque + * DateTime value that, when present, specifies the share snapshot to query. + * + * @type {string} + * @memberof IShareDeleteMethodOptions + */ + sharesnapshot?: string; + + /** + * Specifies the option + * include to delete the base share and all of its snapshots. Possible values + * include: 'include' + * + * @type {Models.DeleteSnapshotsOptionType} + * @memberof IShareDeleteMethodOptions + */ + deleteSnapshots?: Models.DeleteSnapshotsOptionType; +} + +export interface IShareSetMetadataOptions { + /** + * A name-value pair to associate with a file storage object. + * + * @type {{ [propertyName: string]: string }} + * @memberof IShareCreateOptions + */ + metadata?: { [propertyName: string]: string }; +} + +export interface ISignedIdentifier { + /** + * @member {string} id a unique id + */ + id: string; + /** + * @member {AccessPolicy} accessPolicy + */ + accessPolicy: { + /** + * @member {Date} start the date-time the policy is active. + */ + start: Date; + /** + * @member {string} expiry the date-time the policy expires. + */ + expiry: Date; + /** + * @member {string} permission the permissions for the acl policy + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-share-acl + */ + permission: string; + }; +} + +export declare type ShareGetAccessPolicyResponse = { + signedIdentifiers: ISignedIdentifier[]; +} & Models.ShareGetAccessPolicyHeaders & { + /** + * The underlying HTTP response. + */ + _response: HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: Models.ShareGetAccessPolicyHeaders; + /** + * The response body as text (string format) + */ + bodyAsText: string; + /** + * The response body as parsed JSON or XML + */ + parsedBody: Models.SignedIdentifier[]; + }; + }; + +export interface IShareCreateSnapshotOptions { + /** + * A name-value pair to associate with a file storage object. + * + * @type {{ [propertyName: string]: string }} + * @memberof IShareCreateOptions + */ + metadata?: { [propertyName: string]: string }; +} + +/** + * A ShareURL represents a URL to the Azure Storage share allowing you to manipulate its directories and files. + * + * @export + * @class ShareURL + * @extends {StorageURL} + */ +export class ShareURL extends StorageURL { + /** + * Creates a ShareURL object from ServiceURL + * + * @param serviceURL + * @param shareName + */ + public static fromServiceURL( + serviceURL: ServiceURL, + shareName: string + ): ShareURL { + return new ShareURL( + appendToURLPath(serviceURL.url, shareName), + serviceURL.pipeline + ); + } + + /** + * Share operation context provided by protocol layer. + * + * @private + * @type {Share} + * @memberof ShareURL + */ + private context: Share; + + /** + * Creates an instance of ShareURL. + * + * @param {string} url A URL string pointing to Azure Storage file share, such as + * "https://myaccount.file.core.windows.net/share". You can + * append a SAS if using AnonymousCredential, such as + * "https://myaccount.file.core.windows.net/share?sasString". + * @param {Pipeline} pipeline Call StorageURL.newPipeline() to create a default + * pipeline, or provide a customized pipeline. + * @memberof ShareURL + */ + constructor(url: string, pipeline: Pipeline) { + super(url, pipeline); + this.context = new Share(this.storageClientContext); + } + + /** + * Creates a new ShareURL object identical to the source but with the + * specified request policy pipeline. + * + * @param {Pipeline} pipeline + * @returns {ShareURL} + * @memberof ShareURL + */ + public withPipeline(pipeline: Pipeline): ShareURL { + return new ShareURL(this.url, pipeline); + } + + /** + * Creates a new ShareURL object identical to the source but with the specified snapshot timestamp. + * Provide "" will remove the snapshot and return a URL to the base share. + * + * @param {string} snapshot + * @returns {ShareURL} A new ShareURL object identical to the source but with the specified snapshot timestamp + * @memberof ShareURL + */ + public withSnapshot(snapshot: string): ShareURL { + return new ShareURL( + setURLParameter( + this.url, + URLConstants.Parameters.SNAPSHOT, + snapshot.length === 0 ? undefined : snapshot + ), + this.pipeline + ); + } + + /** + * Creates a new share under the specified account. If the share with + * the same name already exists, the operation fails. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/create-share + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IShareCreateOptions} [options] + * @returns {Promise} + * @memberof ShareURL + */ + public async create( + aborter: Aborter, + options: IShareCreateOptions = {} + ): Promise { + return this.context.create({ + ...options, + abortSignal: aborter + }); + } + + /** + * Returns all user-defined metadata and system properties for the specified + * share. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/get-share-properties + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IShareGetPropertiesOptions} [options] + * @returns {Promise} + * @memberof ShareURL + */ + public async getProperties( + aborter: Aborter, + options: IShareGetPropertiesOptions = {} + ): Promise { + return this.context.getProperties({ + abortSignal: aborter, + ...options + }); + } + + /** + * Marks the specified share for deletion. The share and any directories or files + * contained within it are later deleted during garbage collection. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/delete-share + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {Models.IShareDeleteMethodOptions} [options] + * @returns {Promise} + * @memberof ShareURL + */ + public async delete( + aborter: Aborter, + options: IShareDeleteMethodOptions = {} + ): Promise { + return this.context.deleteMethod({ + abortSignal: aborter, + ...options + }); + } + + /** + * Sets one or more user-defined name-value pairs for the specified share. + * + * If no option provided, or no metadata defined in the option parameter, the share + * metadata will be removed. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-share-metadata + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IShareSetMetadataOptions} [options] + * @returns {Promise} + * @memberof ShareURL + */ + public async setMetadata( + aborter: Aborter, + options: IShareSetMetadataOptions = {} + ): Promise { + return this.context.setMetadata({ + abortSignal: aborter, + ...options + }); + } + + /** + * Gets the permissions for the specified share. The permissions indicate + * whether share data may be accessed publicly. + * + * WARNING: JavaScript Date will potential lost precision when parsing start and expiry string. + * For example, new Date("2018-12-31T03:44:23.8827891Z").toISOString() will get "2018-12-31T03:44:23.882Z". + * + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/get-share-acl + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @returns {Promise} + * @memberof ShareURL + */ + public async getAccessPolicy( + aborter: Aborter + ): Promise { + const response = await this.context.getAccessPolicy({ + abortSignal: aborter + }); + + const res: ShareGetAccessPolicyResponse = { + _response: response._response, + date: response.date, + eTag: response.eTag, + errorCode: response.errorCode, + lastModified: response.lastModified, + requestId: response.requestId, + signedIdentifiers: [], + version: response.version + }; + + for (const identifier of response) { + res.signedIdentifiers.push({ + accessPolicy: { + expiry: new Date(identifier.accessPolicy!.expiry!), + permission: identifier.accessPolicy!.permission!, + start: new Date(identifier.accessPolicy!.start!) + }, + id: identifier.id + }); + } + + return res; + } + + /** + * Sets the permissions for the specified share. The permissions indicate + * whether directories or files in a share may be accessed publicly. + * + * When you set permissions for a share, the existing permissions are replaced. + * If no shareAcl provided, the existing share ACL will be + * removed. + * @see https://docs.microsoft.com/en-us/rest/api/storageservices/set-share-acl + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {ISignedIdentifier[]} [shareAcl] + * @returns {Promise} + * @memberof ShareURL + */ + public async setAccessPolicy( + aborter: Aborter, + shareAcl?: ISignedIdentifier[] + ): Promise { + const acl: Models.SignedIdentifier[] = []; + for (const identifier of shareAcl || []) { + acl.push({ + accessPolicy: { + expiry: truncatedISO8061Date(identifier.accessPolicy.expiry), + permission: identifier.accessPolicy.permission, + start: truncatedISO8061Date(identifier.accessPolicy.start) + }, + id: identifier.id + }); + } + + return this.context.setAccessPolicy({ + abortSignal: aborter, + shareAcl: acl + }); + } + + /** + * Creates a read-only snapshot of a share. + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {IShareCreateSnapshotOptions} [options={}] + * @returns {Promise} + * @memberof ShareURL + */ + public async createSnapshot( + aborter: Aborter, + options: IShareCreateSnapshotOptions = {} + ): Promise { + return this.context.createSnapshot({ + abortSignal: aborter, + ...options + }); + } + + /** + * Sets quota for the specified share. + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {number} quotaInGB Specifies the maximum size of the share in gigabytes + * @returns {Promise} + * @memberof ShareURL + */ + public async setQuota( + aborter: Aborter, + quotaInGB: number + ): Promise { + if (quotaInGB <= 0 || quotaInGB > 5120) { + throw new RangeError( + `Share quota must be greater than 0, and less than or equal to 5Tib (5120GB)` + ); + } + return this.context.setQuota({ + abortSignal: aborter, + quota: quotaInGB + }); + } + + /** + * Retrieves statistics related to the share. + * + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @returns {Promise} + * @memberof ShareURL + */ + public async getStatistics( + aborter: Aborter + ): Promise { + return this.context.getStatistics({ + abortSignal: aborter + }); + } +} diff --git a/file/lib/StorageURL.ts b/file/lib/StorageURL.ts new file mode 100644 index 0000000..46af1b4 --- /dev/null +++ b/file/lib/StorageURL.ts @@ -0,0 +1,118 @@ +import { deserializationPolicy, RequestPolicyFactory } from "ms-rest-js"; + +import { BrowserPolicyFactory } from "./BrowserPolicyFactory"; +import { Credential } from "./credentials/Credential"; +import { StorageClientContext } from "./generated/storageClientContext"; +import { LoggingPolicyFactory } from "./LoggingPolicyFactory"; +import { IHttpClient, IHttpPipelineLogger, Pipeline } from "./Pipeline"; +import { IRetryOptions, RetryPolicyFactory } from "./RetryPolicyFactory"; +import { + ITelemetryOptions, + TelemetryPolicyFactory +} from "./TelemetryPolicyFactory"; +import { UniqueRequestIDPolicyFactory } from "./UniqueRequestIDPolicyFactory"; +import { SERVICE_VERSION } from "./utils/constants"; + +export { deserializationPolicy }; + +/** + * Option interface for Pipeline.newPipeline method. + * + * @export + * @interface INewPipelineOptions + */ +export interface INewPipelineOptions { + /** + * Telemetry configures the built-in telemetry policy behavior. + * + * @type {ITelemetryOptions} + * @memberof INewPipelineOptions + */ + telemetry?: ITelemetryOptions; + retryOptions?: IRetryOptions; + + logger?: IHttpPipelineLogger; + httpClient?: IHttpClient; +} + +/** + * A ServiceURL represents a based URL class for ServiceURL, ContainerURL and etc. + * + * @export + * @class StorageURL + */ +export abstract class StorageURL { + /** + * A static method used to create a new Pipeline object with Credential provided. + * + * @static + * @param {Credential} credential Such as AnonymousCredential, SharedKeyCredential or TokenCredential. + * @param {INewPipelineOptions} [pipelineOptions] Optional. Options. + * @returns {Pipeline} A new Pipeline object. + * @memberof Pipeline + */ + public static newPipeline( + credential: Credential, + pipelineOptions: INewPipelineOptions = {} + ): Pipeline { + // Order is important. Closer to the API at the top & closer to the network at the bottom. + // The credential's policy factory must appear close to the wire so it can sign any + // changes made by other factories (like UniqueRequestIDPolicyFactory) + const factories: RequestPolicyFactory[] = []; + factories.push(new TelemetryPolicyFactory(pipelineOptions.telemetry)); + factories.push(new UniqueRequestIDPolicyFactory()); + factories.push(new BrowserPolicyFactory()); + factories.push(deserializationPolicy()); // Default deserializationPolicy is provided by protocol layer + factories.push(new RetryPolicyFactory(pipelineOptions.retryOptions)); + factories.push(new LoggingPolicyFactory()); + factories.push(credential); + + return new Pipeline(factories, { + HTTPClient: pipelineOptions.httpClient, + logger: pipelineOptions.logger + }); + } + + /** + * Request policy pipeline. + * + * @internal + * @type {Pipeline} + * @memberof StorageURL + */ + public readonly pipeline: Pipeline; + + /** + * URL string value. + * + * @type {string} + * @memberof StorageURL + */ + public readonly url: string; + + /** + * StorageClient is a reference to protocol layer operations entry, which is + * generated by AutoRest generator. + * + * @protected + * @type {StorageClient} + * @memberof StorageURL + */ + protected readonly storageClientContext: StorageClientContext; + + /** + * Creates an instance of StorageURL. + * @param {string} url + * @param {Pipeline} pipeline + * @memberof StorageURL + */ + protected constructor(url: string, pipeline: Pipeline) { + this.url = url; + this.pipeline = pipeline; + this.storageClientContext = new StorageClientContext( + url, + SERVICE_VERSION, + pipeline.toServiceClientOptions() + ); + } +} diff --git a/file/lib/TelemetryPolicyFactory.ts b/file/lib/TelemetryPolicyFactory.ts new file mode 100644 index 0000000..53a80a0 --- /dev/null +++ b/file/lib/TelemetryPolicyFactory.ts @@ -0,0 +1,75 @@ +import { + isNode, + RequestPolicy, + RequestPolicyFactory, + RequestPolicyOptions +} from "ms-rest-js"; +import * as os from "os"; + +import { TelemetryPolicy } from "./policies/TelemetryPolicy"; +import { SDK_VERSION } from "./utils/constants"; + +/** + * Interface of TelemetryPolicy options. + * + * @export + * @interface ITelemetryOptions + */ +export interface ITelemetryOptions { + value: string; +} + +/** + * TelemetryPolicyFactory is a factory class helping generating TelemetryPolicy objects. + * + * @export + * @class TelemetryPolicyFactory + * @implements {RequestPolicyFactory} + */ +export class TelemetryPolicyFactory implements RequestPolicyFactory { + private telemetryString: string; + + /** + * Creates an instance of TelemetryPolicyFactory. + * @param {ITelemetryOptions} [telemetry] + * @memberof TelemetryPolicyFactory + */ + constructor(telemetry?: ITelemetryOptions) { + const userAgentInfo: string[] = []; + + if (isNode) { + if (telemetry) { + const telemetryString = telemetry.value; + if ( + telemetryString.length > 0 && + userAgentInfo.indexOf(telemetryString) === -1 + ) { + userAgentInfo.push(telemetryString); + } + } + + // e.g. Azure-Storage/10.0.0 + const libInfo = `Azure-Storage/${SDK_VERSION}`; + if (userAgentInfo.indexOf(libInfo) === -1) { + userAgentInfo.push(libInfo); + } + + // e.g. (NODE-VERSION 4.9.1; Windows_NT 10.0.16299) + const runtimeInfo = `(NODE-VERSION ${ + process.version + }; ${os.type()} ${os.release()})`; + if (userAgentInfo.indexOf(runtimeInfo) === -1) { + userAgentInfo.push(runtimeInfo); + } + } + + this.telemetryString = userAgentInfo.join(" "); + } + + public create( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions + ): TelemetryPolicy { + return new TelemetryPolicy(nextPolicy, options, this.telemetryString); + } +} diff --git a/file/lib/UniqueRequestIDPolicyFactory.ts b/file/lib/UniqueRequestIDPolicyFactory.ts new file mode 100644 index 0000000..6337534 --- /dev/null +++ b/file/lib/UniqueRequestIDPolicyFactory.ts @@ -0,0 +1,19 @@ +import { RequestPolicy, RequestPolicyFactory, RequestPolicyOptions } from "ms-rest-js"; + +import { UniqueRequestIDPolicy } from "./policies/UniqueRequestIDPolicy"; + +/** + * UniqueRequestIDPolicyFactory is a factory class helping generating UniqueRequestIDPolicy objects. + * + * @export + * @class UniqueRequestIDPolicyFactory + * @implements {RequestPolicyFactory} + */ +export class UniqueRequestIDPolicyFactory implements RequestPolicyFactory { + public create( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions + ): UniqueRequestIDPolicy { + return new UniqueRequestIDPolicy(nextPolicy, options); + } +} diff --git a/file/lib/credentials/AnonymousCredential.ts b/file/lib/credentials/AnonymousCredential.ts new file mode 100644 index 0000000..63d3a98 --- /dev/null +++ b/file/lib/credentials/AnonymousCredential.ts @@ -0,0 +1,31 @@ +import { RequestPolicy, RequestPolicyOptions } from "ms-rest-js"; + +import { AnonymousCredentialPolicy } from "../policies/AnonymousCredentialPolicy"; +import { Credential } from "./Credential"; + +/** + * 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). + * + * @export + * @class AnonymousCredential + * @extends {Credential} + */ +export class AnonymousCredential extends Credential { + /** + * Creates an AnonymousCredentialPolicy object. + * + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @returns {AnonymousCredentialPolicy} + * @memberof AnonymousCredential + */ + public create( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions + ): AnonymousCredentialPolicy { + return new AnonymousCredentialPolicy(nextPolicy, options); + } +} diff --git a/file/lib/credentials/Credential.ts b/file/lib/credentials/Credential.ts new file mode 100644 index 0000000..c157d52 --- /dev/null +++ b/file/lib/credentials/Credential.ts @@ -0,0 +1,42 @@ +import { + RequestPolicy, + RequestPolicyFactory, + RequestPolicyOptions +} from "ms-rest-js"; + +import { CredentialPolicy } from "../policies/CredentialPolicy"; + +/** + * Credential is an abstract class for Azure Storage HTTP requests signing. This + * class will host an credentialPolicyCreator factory which generates CredentialPolicy. + * + * @export + * @abstract + * @class Credential + */ +export abstract class Credential implements RequestPolicyFactory { + /** + * Creates a RequestPolicy object. + * + * @param {RequestPolicy} _nextPolicy + * @param {RequestPolicyOptions} _options + * @returns {RequestPolicy} + * @memberof Credential + */ + public create( + // tslint:disable-next-line:variable-name + _nextPolicy: RequestPolicy, + // tslint:disable-next-line:variable-name + _options: RequestPolicyOptions + ): RequestPolicy { + throw new Error("Method should be implemented in children classes."); + } +} + +/** + * A factory function that creates a new CredentialPolicy that uses the provided nextPolicy. + */ +export type CredentialPolicyCreator = ( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions +) => CredentialPolicy; diff --git a/file/lib/credentials/SharedKeyCredential.ts b/file/lib/credentials/SharedKeyCredential.ts new file mode 100644 index 0000000..0db8299 --- /dev/null +++ b/file/lib/credentials/SharedKeyCredential.ts @@ -0,0 +1,72 @@ +import * as Crypto from "crypto"; +import { RequestPolicy, RequestPolicyOptions } from "ms-rest-js"; + +import { SharedKeyCredentialPolicy } from "../policies/SharedKeyCredentialPolicy"; +import { Credential } from "./Credential"; + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * SharedKeyCredential for account key authorization of Azure Storage service. + * + * @export + * @class SharedKeyCredential + * @extends {Credential} + */ +export class SharedKeyCredential extends Credential { + /** + * Azure Storage account name; readonly. + * + * @type {string} + * @memberof SharedKeyCredential + */ + public readonly accountName: string; + + /** + * Azure Storage account key; readonly. + * + * @type {Buffer} + * @memberof SharedKeyCredential + */ + private readonly accountKey: Buffer; + + /** + * Creates an instance of SharedKeyCredential. + * @param {string} accountName + * @param {string} accountKey + * @memberof SharedKeyCredential + */ + constructor(accountName: string, accountKey: string) { + super(); + this.accountName = accountName; + this.accountKey = Buffer.from(accountKey, "base64"); + } + + /** + * Creates a SharedKeyCredentialPolicy object. + * + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @returns {SharedKeyCredentialPolicy} + * @memberof SharedKeyCredential + */ + public create( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions + ): SharedKeyCredentialPolicy { + return new SharedKeyCredentialPolicy(nextPolicy, options, this); + } + + /** + * Generates a hash signature for an HTTP request or for a SAS. + * + * @param {string} stringToSign + * @returns {string} + * @memberof SharedKeyCredential + */ + public computeHMACSHA256(stringToSign: string): string { + return Crypto.createHmac("sha256", this.accountKey) + .update(stringToSign, "utf8") + .digest("base64"); + } +} diff --git a/file/lib/credentials/TokenCredential.ts b/file/lib/credentials/TokenCredential.ts new file mode 100644 index 0000000..2778c04 --- /dev/null +++ b/file/lib/credentials/TokenCredential.ts @@ -0,0 +1,65 @@ +import { RequestPolicy, RequestPolicyOptions } from "ms-rest-js"; + +import { Credential } from "../credentials/Credential"; +import { TokenCredentialPolicy } from "../policies/TokenCredentialPolicy"; + +/** + * TokenCredential is a Credential used to generate a TokenCredentialPolicy. + * Renew token by setting a new token string value to token property. + * + * @example + * const tokenCredential = new TokenCredential("token"); + * const pipeline = StorageURL.newPipeline(tokenCredential); + * + * // List containers + * const serviceURL = new ServiceURL("https://mystorageaccount.blob.core.windows.net", pipeline); + * + * // Set up a timer to refresh the token + * const timerID = setInterval(() => { + * // Update token by accessing to public tokenCredential.token + * tokenCredential.token = "updatedToken"; + * // WARNING: Timer must be manually stopped! It will forbid GC of tokenCredential + * if (shouldStop()) { + * clearInterval(timerID); + * } + * }, 60 * 60 * 1000); // Set an interval time before your token expired + * @export + * @class TokenCredential + * @extends {Credential} + * + */ +export class TokenCredential extends Credential { + /** + * Mutable token value. You can set a renewed token value to this property, + * for example, when an OAuth token is expired. + * + * @type {string} + * @memberof TokenCredential + */ + public token: string; + + /** + * Creates an instance of TokenCredential. + * @param {string} token + * @memberof TokenCredential + */ + constructor(token: string) { + super(); + this.token = token; + } + + /** + * Creates a TokenCredentialPolicy object. + * + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @returns {TokenCredentialPolicy} + * @memberof TokenCredential + */ + public create( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions + ): TokenCredentialPolicy { + return new TokenCredentialPolicy(nextPolicy, options, this); + } +} diff --git a/file/lib/generated/models/directoryMappers.ts b/file/lib/generated/models/directoryMappers.ts new file mode 100644 index 0000000..72153be --- /dev/null +++ b/file/lib/generated/models/directoryMappers.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +export { + discriminators, + DirectoryCreateHeaders, + StorageError, + DirectoryGetPropertiesHeaders, + DirectoryDeleteHeaders, + DirectorySetMetadataHeaders, + ListFilesAndDirectoriesSegmentResponse, + Entry, + DirectoryListFilesAndDirectoriesSegmentHeaders, + DirectoryItem, + FileItem, + FileProperty +} from "../models/mappers"; + diff --git a/file/lib/generated/models/fileMappers.ts b/file/lib/generated/models/fileMappers.ts new file mode 100644 index 0000000..1f09fae --- /dev/null +++ b/file/lib/generated/models/fileMappers.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +export { + discriminators, + FileCreateHeaders, + StorageError, + FileDownloadHeaders, + FileGetPropertiesHeaders, + FileDeleteHeaders, + FileSetHTTPHeadersHeaders, + FileSetMetadataHeaders, + FileUploadRangeHeaders, + Range, + FileGetRangeListHeaders, + FileStartCopyHeaders, + FileAbortCopyHeaders +} from "../models/mappers"; + diff --git a/file/lib/generated/models/index.ts b/file/lib/generated/models/index.ts new file mode 100644 index 0000000..88ba423 --- /dev/null +++ b/file/lib/generated/models/index.ts @@ -0,0 +1,2877 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "ms-rest-js"; + + +/** + * @interface + * An interface representing AccessPolicy. + * An Access policy. + * + */ +export interface AccessPolicy { + /** + * @member {string} [start] The date-time the policy is active. + * **NOTE: This entity will be treated as a string instead of a Date because + * the API can potentially deal with a higher precision value than what is + * supported by JavaScript.** + */ + start?: string; + /** + * @member {string} [expiry] The date-time the policy expires. + * **NOTE: This entity will be treated as a string instead of a Date because + * the API can potentially deal with a higher precision value than what is + * supported by JavaScript.** + */ + expiry?: string; + /** + * @member {string} [permission] The permissions for the ACL policy. + */ + permission?: string; +} + +/** + * @interface + * An interface representing CorsRule. + * CORS is an HTTP feature that enables a web application running under one + * domain to access resources in another domain. Web browsers implement a + * security restriction known as same-origin policy that prevents a web page + * from calling APIs in a different domain; CORS provides a secure way to allow + * one domain (the origin domain) to call APIs in another domain. + * + */ +export interface CorsRule { + /** + * @member {string} allowedOrigins The origin domains that are permitted to + * make a request against the storage service via CORS. The origin domain is + * the domain from which the request originates. Note that the origin must be + * an exact case-sensitive match with the origin that the user age sends to + * the service. You can also use the wildcard character '*' to allow all + * origin domains to make requests via CORS. + */ + allowedOrigins: string; + /** + * @member {string} allowedMethods The methods (HTTP request verbs) that the + * origin domain may use for a CORS request. (comma separated) + */ + allowedMethods: string; + /** + * @member {string} allowedHeaders The request headers that the origin domain + * may specify on the CORS request. + */ + allowedHeaders: string; + /** + * @member {string} exposedHeaders The response headers that may be sent in + * the response to the CORS request and exposed by the browser to the request + * issuer. + */ + exposedHeaders: string; + /** + * @member {number} maxAgeInSeconds The maximum amount time that a browser + * should cache the preflight OPTIONS request. + */ + maxAgeInSeconds: number; +} + +/** + * Contains the possible cases for Entry. + */ +export type EntryUnion = Entry | DirectoryItem | FileItem; + +/** + * @interface + * An interface representing Entry. + * Abstract for entries that can be listed from Directory. + * + */ +export interface Entry { + /** + * @member {string} entryType Polymorphic Discriminator + */ + entryType: "Entry"; + /** + * @member {string} name Name of the entry. + */ + name: string; +} + +/** + * @interface + * An interface representing DirectoryItem. + * A listed directory item. + * + */ +export interface DirectoryItem { + /** + * @member {string} entryType Polymorphic Discriminator + */ + entryType: "Directory"; + /** + * @member {string} name Name of the entry. + */ + name: string; +} + +/** + * @interface + * An interface representing FileProperty. + * File properties. + * + */ +export interface FileProperty { + /** + * @member {number} contentLength Content length of the file. This value may + * not be up-to-date since an SMB client may have modified the file locally. + * The value of Content-Length may not reflect that fact until the handle is + * closed or the op-lock is broken. To retrieve current property values, call + * Get File Properties. + */ + contentLength: number; +} + +/** + * @interface + * An interface representing FileItem. + * A listed file item. + * + */ +export interface FileItem { + /** + * @member {string} entryType Polymorphic Discriminator + */ + entryType: "File"; + /** + * @member {string} name Name of the entry. + */ + name: string; + /** + * @member {FileProperty} properties + */ + properties: FileProperty; +} + +/** + * @interface + * An interface representing ListFilesAndDirectoriesSegmentResponse. + * An enumeration of directories and files. + * + */ +export interface ListFilesAndDirectoriesSegmentResponse { + /** + * @member {string} serviceEndpoint + */ + serviceEndpoint: string; + /** + * @member {string} shareName + */ + shareName: string; + /** + * @member {string} [shareSnapshot] + */ + shareSnapshot?: string; + /** + * @member {string} directoryPath + */ + directoryPath: string; + /** + * @member {string} prefix + */ + prefix: string; + /** + * @member {string} [marker] + */ + marker?: string; + /** + * @member {number} [maxResults] + */ + maxResults?: number; + /** + * @member {EntryUnion[]} [entries] + */ + entries?: EntryUnion[]; + /** + * @member {string} nextMarker + */ + nextMarker: string; +} + +/** + * @interface + * An interface representing ShareProperties. + * Properties of a share. + * + */ +export interface ShareProperties { + /** + * @member {Date} lastModified + */ + lastModified: Date; + /** + * @member {string} etag + */ + etag: string; + /** + * @member {number} quota + */ + quota: number; +} + +/** + * @interface + * An interface representing ShareItem. + * A listed Azure Storage share item. + * + */ +export interface ShareItem { + /** + * @member {string} name + */ + name: string; + /** + * @member {string} [snapshot] + */ + snapshot?: string; + /** + * @member {ShareProperties} properties + */ + properties: ShareProperties; + /** + * @member {{ [propertyName: string]: string }} [metadata] + */ + metadata?: { [propertyName: string]: string }; +} + +/** + * @interface + * An interface representing ListSharesResponse. + * An enumeration of shares. + * + */ +export interface ListSharesResponse { + /** + * @member {string} serviceEndpoint + */ + serviceEndpoint: string; + /** + * @member {string} [prefix] + */ + prefix?: string; + /** + * @member {string} [marker] + */ + marker?: string; + /** + * @member {number} [maxResults] + */ + maxResults?: number; + /** + * @member {ShareItem[]} [shareItems] + */ + shareItems?: ShareItem[]; + /** + * @member {string} nextMarker + */ + nextMarker: string; +} + +/** + * @interface + * An interface representing RetentionPolicy. + * The retention policy. + * + */ +export interface RetentionPolicy { + /** + * @member {boolean} enabled Indicates whether a retention policy is enabled + * for the File service. If false, metrics data is retained, and the user is + * responsible for deleting it. + */ + enabled: boolean; + /** + * @member {number} [days] Indicates the number of days that metrics data + * should be retained. All data older than this value will be deleted. + * Metrics data is deleted on a best-effort basis after the retention period + * expires. + */ + days?: number; +} + +/** + * @interface + * An interface representing Metrics. + * Storage Analytics metrics for file service. + * + */ +export interface Metrics { + /** + * @member {string} version The version of Storage Analytics to configure. + */ + version: string; + /** + * @member {boolean} enabled Indicates whether metrics are enabled for the + * File service. + */ + enabled: boolean; + /** + * @member {boolean} [includeAPIs] Indicates whether metrics should generate + * summary statistics for called API operations. + */ + includeAPIs?: boolean; + /** + * @member {RetentionPolicy} [retentionPolicy] + */ + retentionPolicy?: RetentionPolicy; +} + +/** + * @interface + * An interface representing Range. + * An Azure Storage file range. + * + */ +export interface Range { + /** + * @member {number} start Start of the range. + */ + start: number; + /** + * @member {number} end End of the range. + */ + end: number; +} + +/** + * @interface + * An interface representing StorageError. + */ +export interface StorageError { + /** + * @member {string} [message] + */ + message?: string; +} + +/** + * @interface + * An interface representing ShareStats. + * Stats for the share. + * + */ +export interface ShareStats { + /** + * @member {number} shareUsage The approximate size of the data stored on the + * share, rounded up to the nearest gigabyte. Note that this value may not + * include all recently created or recently resized files. + */ + shareUsage: number; +} + +/** + * @interface + * An interface representing SignedIdentifier. + * Signed identifier. + * + */ +export interface SignedIdentifier { + /** + * @member {string} id A unique id. + */ + id: string; + /** + * @member {AccessPolicy} [accessPolicy] The access policy. + */ + accessPolicy?: AccessPolicy; +} + +/** + * @interface + * An interface representing StorageServiceProperties. + * Storage service properties. + * + */ +export interface StorageServiceProperties { + /** + * @member {Metrics} [hourMetrics] A summary of request statistics grouped by + * API in hourly aggregates for files. + */ + hourMetrics?: Metrics; + /** + * @member {Metrics} [minuteMetrics] A summary of request statistics grouped + * by API in minute aggregates for files. + */ + minuteMetrics?: Metrics; + /** + * @member {CorsRule[]} [cors] The set of CORS rules. + */ + cors?: CorsRule[]; +} + +/** + * @interface + * An interface representing ServiceSetPropertiesOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ServiceSetPropertiesOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing ServiceGetPropertiesOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ServiceGetPropertiesOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing ServiceListSharesSegmentOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ServiceListSharesSegmentOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {string} [prefix] Filters the results to return only entries whose + * name begins with the specified prefix. + */ + prefix?: string; + /** + * @member {string} [marker] A string value that identifies the portion of + * the list to be returned with the next list operation. The operation + * returns a marker value within the response body if the list returned was + * not complete. The marker value may then be used in a subsequent call to + * request the next set of list items. The marker value is opaque to the + * client. + */ + marker?: string; + /** + * @member {number} [maxresults] Specifies the maximum number of entries to + * return. If the request does not specify maxresults, or specifies a value + * greater than 5,000, the server will return up to 5,000 items. + */ + maxresults?: number; + /** + * @member {ListSharesIncludeType[]} [include] Include this parameter to + * specify one or more datasets to include in the response. + */ + include?: ListSharesIncludeType[]; + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing ShareCreateOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ShareCreateOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {{ [propertyName: string]: string }} [metadata] A name-value pair + * to associate with a file storage object. + */ + metadata?: { [propertyName: string]: string }; + /** + * @member {number} [quota] Specifies the maximum size of the share, in + * gigabytes. + */ + quota?: number; +} + +/** + * @interface + * An interface representing ShareGetPropertiesOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ShareGetPropertiesOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {string} [sharesnapshot] The snapshot parameter is an opaque + * DateTime value that, when present, specifies the share snapshot to query. + */ + sharesnapshot?: string; + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing ShareDeleteMethodOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ShareDeleteMethodOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {string} [sharesnapshot] The snapshot parameter is an opaque + * DateTime value that, when present, specifies the share snapshot to query. + */ + sharesnapshot?: string; + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {DeleteSnapshotsOptionType} [deleteSnapshots] Specifies the option + * include to delete the base share and all of its snapshots. Possible values + * include: 'include' + */ + deleteSnapshots?: DeleteSnapshotsOptionType; +} + +/** + * @interface + * An interface representing ShareCreateSnapshotOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ShareCreateSnapshotOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {{ [propertyName: string]: string }} [metadata] A name-value pair + * to associate with a file storage object. + */ + metadata?: { [propertyName: string]: string }; +} + +/** + * @interface + * An interface representing ShareSetQuotaOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ShareSetQuotaOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {number} [quota] Specifies the maximum size of the share, in + * gigabytes. + */ + quota?: number; +} + +/** + * @interface + * An interface representing ShareSetMetadataOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ShareSetMetadataOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {{ [propertyName: string]: string }} [metadata] A name-value pair + * to associate with a file storage object. + */ + metadata?: { [propertyName: string]: string }; +} + +/** + * @interface + * An interface representing ShareGetAccessPolicyOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ShareGetAccessPolicyOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing ShareSetAccessPolicyOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ShareSetAccessPolicyOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {SignedIdentifier[]} [shareAcl] The ACL for the share. + */ + shareAcl?: SignedIdentifier[]; + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing ShareGetStatisticsOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface ShareGetStatisticsOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing DirectoryCreateOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface DirectoryCreateOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {{ [propertyName: string]: string }} [metadata] A name-value pair + * to associate with a file storage object. + */ + metadata?: { [propertyName: string]: string }; +} + +/** + * @interface + * An interface representing DirectoryGetPropertiesOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface DirectoryGetPropertiesOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {string} [sharesnapshot] The snapshot parameter is an opaque + * DateTime value that, when present, specifies the share snapshot to query. + */ + sharesnapshot?: string; + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing DirectoryDeleteMethodOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface DirectoryDeleteMethodOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing DirectorySetMetadataOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface DirectorySetMetadataOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {{ [propertyName: string]: string }} [metadata] A name-value pair + * to associate with a file storage object. + */ + metadata?: { [propertyName: string]: string }; +} + +/** + * @interface + * An interface representing DirectoryListFilesAndDirectoriesSegmentOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface DirectoryListFilesAndDirectoriesSegmentOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {string} [prefix] Filters the results to return only entries whose + * name begins with the specified prefix. + */ + prefix?: string; + /** + * @member {string} [sharesnapshot] The snapshot parameter is an opaque + * DateTime value that, when present, specifies the share snapshot to query. + */ + sharesnapshot?: string; + /** + * @member {string} [marker] A string value that identifies the portion of + * the list to be returned with the next list operation. The operation + * returns a marker value within the response body if the list returned was + * not complete. The marker value may then be used in a subsequent call to + * request the next set of list items. The marker value is opaque to the + * client. + */ + marker?: string; + /** + * @member {number} [maxresults] Specifies the maximum number of entries to + * return. If the request does not specify maxresults, or specifies a value + * greater than 5,000, the server will return up to 5,000 items. + */ + maxresults?: number; + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing FileCreateOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileCreateOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {string} [fileContentType] Sets the MIME content type of the file. + * The default type is 'application/octet-stream'. + */ + fileContentType?: string; + /** + * @member {string} [fileContentEncoding] Specifies which content encodings + * have been applied to the file. + */ + fileContentEncoding?: string; + /** + * @member {string} [fileContentLanguage] Specifies the natural languages + * used by this resource. + */ + fileContentLanguage?: string; + /** + * @member {string} [fileCacheControl] Sets the file's cache control. The + * File service stores this value but does not use or modify it. + */ + fileCacheControl?: string; + /** + * @member {Uint8Array} [fileContentMD5] Sets the file's MD5 hash. + */ + fileContentMD5?: Uint8Array; + /** + * @member {string} [fileContentDisposition] Sets the file's + * Content-Disposition header. + */ + fileContentDisposition?: string; + /** + * @member {{ [propertyName: string]: string }} [metadata] A name-value pair + * to associate with a file storage object. + */ + metadata?: { [propertyName: string]: string }; +} + +/** + * @interface + * An interface representing FileDownloadOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileDownloadOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {string} [range] Return file data only from the specified byte + * range. + */ + range?: string; + /** + * @member {boolean} [rangeGetContentMD5] When this header is set to true and + * specified together with the Range header, the service returns the MD5 hash + * for the range, as long as the range is less than or equal to 4 MB in size. + */ + rangeGetContentMD5?: boolean; +} + +/** + * @interface + * An interface representing FileGetPropertiesOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileGetPropertiesOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {string} [sharesnapshot] The snapshot parameter is an opaque + * DateTime value that, when present, specifies the share snapshot to query. + */ + sharesnapshot?: string; + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing FileDeleteMethodOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileDeleteMethodOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing FileSetHTTPHeadersOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileSetHTTPHeadersOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {number} [fileContentLength] Resizes a file to the specified size. + * If the specified byte value is less than the current size of the file, + * then all ranges above the specified byte value are cleared. + */ + fileContentLength?: number; + /** + * @member {string} [fileContentType] Sets the MIME content type of the file. + * The default type is 'application/octet-stream'. + */ + fileContentType?: string; + /** + * @member {string} [fileContentEncoding] Specifies which content encodings + * have been applied to the file. + */ + fileContentEncoding?: string; + /** + * @member {string} [fileContentLanguage] Specifies the natural languages + * used by this resource. + */ + fileContentLanguage?: string; + /** + * @member {string} [fileCacheControl] Sets the file's cache control. The + * File service stores this value but does not use or modify it. + */ + fileCacheControl?: string; + /** + * @member {Uint8Array} [fileContentMD5] Sets the file's MD5 hash. + */ + fileContentMD5?: Uint8Array; + /** + * @member {string} [fileContentDisposition] Sets the file's + * Content-Disposition header. + */ + fileContentDisposition?: string; +} + +/** + * @interface + * An interface representing FileSetMetadataOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileSetMetadataOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {{ [propertyName: string]: string }} [metadata] A name-value pair + * to associate with a file storage object. + */ + metadata?: { [propertyName: string]: string }; +} + +/** + * @interface + * An interface representing FileUploadRangeOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileUploadRangeOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {msRest.HttpRequestBody} [optionalbody] Initial data. + */ + optionalbody?: msRest.HttpRequestBody; + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {Uint8Array} [contentMD5] An MD5 hash of the content. This hash is + * used to verify the integrity of the data during transport. When the + * Content-MD5 header is specified, the File service compares the hash of the + * content that has arrived with the header value that was sent. If the two + * hashes do not match, the operation will fail with error code 400 (Bad + * Request). + */ + contentMD5?: Uint8Array; +} + +/** + * @interface + * An interface representing FileGetRangeListOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileGetRangeListOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {string} [sharesnapshot] The snapshot parameter is an opaque + * DateTime value that, when present, specifies the share snapshot to query. + */ + sharesnapshot?: string; + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {string} [range] Specifies the range of bytes over which to list + * ranges, inclusively. + */ + range?: string; +} + +/** + * @interface + * An interface representing FileStartCopyOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileStartCopyOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; + /** + * @member {{ [propertyName: string]: string }} [metadata] A name-value pair + * to associate with a file storage object. + */ + metadata?: { [propertyName: string]: string }; +} + +/** + * @interface + * An interface representing FileAbortCopyOptionalParams. + * Optional Parameters. + * + * @extends RequestOptionsBase + */ +export interface FileAbortCopyOptionalParams extends msRest.RequestOptionsBase { + /** + * @member {number} [timeout] The timeout parameter is expressed in seconds. + * For more information, see Setting + * Timeouts for File Service Operations. + */ + timeout?: number; +} + +/** + * @interface + * An interface representing ServiceSetPropertiesHeaders. + * Defines headers for SetProperties operation. + * + */ +export interface ServiceSetPropertiesHeaders { + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ServiceGetPropertiesHeaders. + * Defines headers for GetProperties operation. + * + */ +export interface ServiceGetPropertiesHeaders { + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ServiceListSharesSegmentHeaders. + * Defines headers for ListSharesSegment operation. + * + */ +export interface ServiceListSharesSegmentHeaders { + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ShareCreateHeaders. + * Defines headers for Create operation. + * + */ +export interface ShareCreateHeaders { + /** + * @member {string} [eTag] The ETag contains a value which represents the + * version of the share, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. Any operation that modifies the share or its properties or + * metadata updates the last modified time. Operations on files do not affect + * the last modified time of the share. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ShareGetPropertiesHeaders. + * Defines headers for GetProperties operation. + * + */ +export interface ShareGetPropertiesHeaders { + /** + * @member {{ [propertyName: string]: string }} [metadata] + */ + metadata?: { [propertyName: string]: string }; + /** + * @member {string} [eTag] The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. Any operation that modifies the share or its properties updates + * the last modified time. Operations on files do not affect the last + * modified time of the share. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {number} [quota] Returns the current share quota in GB. + */ + quota?: number; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ShareDeleteHeaders. + * Defines headers for Delete operation. + * + */ +export interface ShareDeleteHeaders { + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ShareCreateSnapshotHeaders. + * Defines headers for CreateSnapshot operation. + * + */ +export interface ShareCreateSnapshotHeaders { + /** + * @member {string} [snapshot] This header is a DateTime value that uniquely + * identifies the share snapshot. The value of this header may be used in + * subsequent requests to access the share snapshot. This value is opaque. + */ + snapshot?: string; + /** + * @member {string} [eTag] The ETag contains a value which represents the + * version of the share snapshot, in quotes. A share snapshot cannot be + * modified, so the ETag of a given share snapshot never changes. However, if + * new metadata was supplied with the Snapshot Share request then the ETag of + * the share snapshot differs from that of the base share. If no metadata was + * specified with the request, the ETag of the share snapshot is identical to + * that of the base share at the time the share snapshot was taken. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. A share snapshot cannot be modified, so the last modified time + * of a given share snapshot never changes. However, if new metadata was + * supplied with the Snapshot Share request then the last modified time of + * the share snapshot differs from that of the base share. If no metadata was + * specified with the request, the last modified time of the share snapshot + * is identical to that of the base share at the time the share snapshot was + * taken. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ShareSetQuotaHeaders. + * Defines headers for SetQuota operation. + * + */ +export interface ShareSetQuotaHeaders { + /** + * @member {string} [eTag] The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. Any operation that modifies the share or its properties updates + * the last modified time. Operations on files do not affect the last + * modified time of the share. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ShareSetMetadataHeaders. + * Defines headers for SetMetadata operation. + * + */ +export interface ShareSetMetadataHeaders { + /** + * @member {string} [eTag] The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. Any operation that modifies the share or its properties updates + * the last modified time. Operations on files do not affect the last + * modified time of the share. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ShareGetAccessPolicyHeaders. + * Defines headers for GetAccessPolicy operation. + * + */ +export interface ShareGetAccessPolicyHeaders { + /** + * @member {string} [eTag] The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. Any operation that modifies the share or its properties updates + * the last modified time. Operations on files do not affect the last + * modified time of the share. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ShareSetAccessPolicyHeaders. + * Defines headers for SetAccessPolicy operation. + * + */ +export interface ShareSetAccessPolicyHeaders { + /** + * @member {string} [eTag] The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. Any operation that modifies the share or its properties updates + * the last modified time. Operations on files do not affect the last + * modified time of the share. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing ShareGetStatisticsHeaders. + * Defines headers for GetStatistics operation. + * + */ +export interface ShareGetStatisticsHeaders { + /** + * @member {string} [eTag] The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. Any operation that modifies the share or its properties updates + * the last modified time. Operations on files do not affect the last + * modified time of the share. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing DirectoryCreateHeaders. + * Defines headers for Create operation. + * + */ +export interface DirectoryCreateHeaders { + /** + * @member {string} [eTag] The ETag contains a value which represents the + * version of the directory, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. Any operation that modifies the directory or its properties + * updates the last modified time. Operations on files do not affect the last + * modified time of the directory. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {boolean} [isServerEncrypted] The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing DirectoryGetPropertiesHeaders. + * Defines headers for GetProperties operation. + * + */ +export interface DirectoryGetPropertiesHeaders { + /** + * @member {{ [propertyName: string]: string }} [metadata] + */ + metadata?: { [propertyName: string]: string }; + /** + * @member {string} [eTag] The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the Directory was + * last modified. Operations on files within the directory do not affect the + * last modified time of the directory. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {boolean} [isServerEncrypted] The value of this header is set to + * true if the directory metadata is completely encrypted using the specified + * algorithm. Otherwise, the value is set to false. + */ + isServerEncrypted?: boolean; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing DirectoryDeleteHeaders. + * Defines headers for Delete operation. + * + */ +export interface DirectoryDeleteHeaders { + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing DirectorySetMetadataHeaders. + * Defines headers for SetMetadata operation. + * + */ +export interface DirectorySetMetadataHeaders { + /** + * @member {string} [eTag] The ETag contains a value which represents the + * version of the directory, in quotes. + */ + eTag?: string; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {boolean} [isServerEncrypted] The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing DirectoryListFilesAndDirectoriesSegmentHeaders. + * Defines headers for ListFilesAndDirectoriesSegment operation. + * + */ +export interface DirectoryListFilesAndDirectoriesSegmentHeaders { + /** + * @member {string} [contentType] Specifies the format in which the results + * are returned. Currently this value is 'application/xml'. + */ + contentType?: string; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileCreateHeaders. + * Defines headers for Create operation. + * + */ +export interface FileCreateHeaders { + /** + * @member {string} [eTag] The ETag contains a value which represents the + * version of the file, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the share was last + * modified. Any operation that modifies the directory or its properties + * updates the last modified time. Operations on files do not affect the last + * modified time of the directory. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {boolean} [isServerEncrypted] The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileDownloadHeaders. + * Defines headers for Download operation. + * + */ +export interface FileDownloadHeaders { + /** + * @member {Date} [lastModified] Returns the date and time the file was last + * modified. Any operation that modifies the file or its properties updates + * the last modified time. + */ + lastModified?: Date; + /** + * @member {{ [propertyName: string]: string }} [metadata] + */ + metadata?: { [propertyName: string]: string }; + /** + * @member {number} [contentLength] The number of bytes present in the + * response body. + */ + contentLength?: number; + /** + * @member {string} [contentType] The content type specified for the file. + * The default content type is 'application/octet-stream' + */ + contentType?: string; + /** + * @member {string} [contentRange] Indicates the range of bytes returned if + * the client requested a subset of the file by setting the Range request + * header. + */ + contentRange?: string; + /** + * @member {string} [eTag] The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + */ + eTag?: string; + /** + * @member {Uint8Array} [contentMD5] 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. + */ + contentMD5?: Uint8Array; + /** + * @member {string} [contentEncoding] Returns the value that was specified + * for the Content-Encoding request header. + */ + contentEncoding?: string; + /** + * @member {string} [cacheControl] Returned if it was previously specified + * for the file. + */ + cacheControl?: string; + /** + * @member {string} [contentDisposition] Returns the value that was specified + * for the 'x-ms-content-disposition' header and specifies how to process the + * response. + */ + contentDisposition?: string; + /** + * @member {string} [contentLanguage] Returns the value that was specified + * for the Content-Language request header. + */ + contentLanguage?: string; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {string} [acceptRanges] Indicates that the service supports + * requests for partial file content. + */ + acceptRanges?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {Date} [copyCompletionTime] 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. + */ + copyCompletionTime?: Date; + /** + * @member {string} [copyStatusDescription] Only appears when + * x-ms-copy-status is failed or pending. Describes cause of fatal or + * non-fatal copy operation failure. + */ + copyStatusDescription?: string; + /** + * @member {string} [copyId] String identifier for the last attempted Copy + * File operation where this file was the destination file. + */ + copyId?: string; + /** + * @member {string} [copyProgress] 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. + */ + copyProgress?: string; + /** + * @member {string} [copySource] 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. + */ + copySource?: string; + /** + * @member {CopyStatusType} [copyStatus] State of the copy operation + * identified by 'x-ms-copy-id'. Possible values include: 'pending', + * 'success', 'aborted', 'failed' + */ + copyStatus?: CopyStatusType; + /** + * @member {Uint8Array} [fileContentMD5] If the file 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 file'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. + */ + fileContentMD5?: Uint8Array; + /** + * @member {boolean} [isServerEncrypted] 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). + */ + isServerEncrypted?: boolean; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileGetPropertiesHeaders. + * Defines headers for GetProperties operation. + * + */ +export interface FileGetPropertiesHeaders { + /** + * @member {Date} [lastModified] Returns the date and time the file was last + * modified. The date format follows RFC 1123. Any operation that modifies + * the file or its properties updates the last modified time. + */ + lastModified?: Date; + /** + * @member {{ [propertyName: string]: string }} [metadata] + */ + metadata?: { [propertyName: string]: string }; + /** + * @member {FileType} [fileType] Returns the type File. Reserved for future + * use. Possible values include: 'File' + */ + fileType?: FileType; + /** + * @member {number} [contentLength] The size of the file in bytes. This + * header returns the value of the 'x-ms-content-length' header that is + * stored with the file. + */ + contentLength?: number; + /** + * @member {string} [contentType] The content type specified for the file. + * The default content type is 'application/octet-stream' + */ + contentType?: string; + /** + * @member {string} [eTag] The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + */ + eTag?: string; + /** + * @member {Uint8Array} [contentMD5] If the Content-MD5 header has been set + * for the file, the Content-MD5 response header is returned so that the + * client can check for message content integrity. + */ + contentMD5?: Uint8Array; + /** + * @member {string} [contentEncoding] If the Content-Encoding request header + * has previously been set for the file, the Content-Encoding value is + * returned in this header. + */ + contentEncoding?: string; + /** + * @member {string} [cacheControl] If the Cache-Control request header has + * previously been set for the file, the Cache-Control value is returned in + * this header. + */ + cacheControl?: string; + /** + * @member {string} [contentDisposition] Returns the value that was specified + * for the 'x-ms-content-disposition' header and specifies how to process the + * response. + */ + contentDisposition?: string; + /** + * @member {string} [contentLanguage] Returns the value that was specified + * for the Content-Language request header. + */ + contentLanguage?: string; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {Date} [copyCompletionTime] 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. + */ + copyCompletionTime?: Date; + /** + * @member {string} [copyStatusDescription] Only appears when + * x-ms-copy-status is failed or pending. Describes cause of fatal or + * non-fatal copy operation failure. + */ + copyStatusDescription?: string; + /** + * @member {string} [copyId] String identifier for the last attempted Copy + * File operation where this file was the destination file. + */ + copyId?: string; + /** + * @member {string} [copyProgress] 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. + */ + copyProgress?: string; + /** + * @member {string} [copySource] 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. + */ + copySource?: string; + /** + * @member {CopyStatusType} [copyStatus] State of the copy operation + * identified by 'x-ms-copy-id'. Possible values include: 'pending', + * 'success', 'aborted', 'failed' + */ + copyStatus?: CopyStatusType; + /** + * @member {boolean} [isServerEncrypted] 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). + */ + isServerEncrypted?: boolean; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileDeleteHeaders. + * Defines headers for Delete operation. + * + */ +export interface FileDeleteHeaders { + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileSetHTTPHeadersHeaders. + * Defines headers for SetHTTPHeaders operation. + * + */ +export interface FileSetHTTPHeadersHeaders { + /** + * @member {string} [eTag] The ETag contains a value which represents the + * version of the file, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the directory was + * last modified. Any operation that modifies the directory or its properties + * updates the last modified time. Operations on files do not affect the last + * modified time of the directory. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {boolean} [isServerEncrypted] The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileSetMetadataHeaders. + * Defines headers for SetMetadata operation. + * + */ +export interface FileSetMetadataHeaders { + /** + * @member {string} [eTag] The ETag contains a value which represents the + * version of the file, in quotes. + */ + eTag?: string; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {boolean} [isServerEncrypted] The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileUploadRangeHeaders. + * Defines headers for UploadRange operation. + * + */ +export interface FileUploadRangeHeaders { + /** + * @member {string} [eTag] The ETag contains a value which represents the + * version of the file, in quotes. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date and time the directory was + * last modified. Any operation that modifies the share or its properties or + * metadata updates the last modified time. Operations on files do not affect + * the last modified time of the share. + */ + lastModified?: Date; + /** + * @member {Uint8Array} [contentMD5] This header is returned so that the + * client can check for message content integrity. The value of this header + * is computed by the File service; it is not necessarily the same value as + * may have been specified in the request headers. + */ + contentMD5?: Uint8Array; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {boolean} [isServerEncrypted] The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + */ + isServerEncrypted?: boolean; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileGetRangeListHeaders. + * Defines headers for GetRangeList operation. + * + */ +export interface FileGetRangeListHeaders { + /** + * @member {Date} [lastModified] The date/time that the file was last + * modified. Any operation that modifies the file, including an update of the + * file's metadata or properties, changes the file's last modified time. + */ + lastModified?: Date; + /** + * @member {string} [eTag] The ETag contains a value which represents the + * version of the file, in quotes. + */ + eTag?: string; + /** + * @member {number} [fileContentLength] The size of the file in bytes. + */ + fileContentLength?: number; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileStartCopyHeaders. + * Defines headers for StartCopy operation. + * + */ +export interface FileStartCopyHeaders { + /** + * @member {string} [eTag] If the copy is completed, contains the ETag of the + * destination file. If the copy is not complete, contains the ETag of the + * empty file created at the start of the copy. + */ + eTag?: string; + /** + * @member {Date} [lastModified] Returns the date/time that the copy + * operation to the destination file completed. + */ + lastModified?: Date; + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [copyId] String identifier for this copy operation. Use + * with Get File or Get File Properties to check the status of this copy + * operation, or pass to Abort Copy File to abort a pending copy. + */ + copyId?: string; + /** + * @member {CopyStatusType} [copyStatus] State of the copy operation + * identified by x-ms-copy-id. Possible values include: 'pending', 'success', + * 'aborted', 'failed' + */ + copyStatus?: CopyStatusType; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * @interface + * An interface representing FileAbortCopyHeaders. + * Defines headers for AbortCopy operation. + * + */ +export interface FileAbortCopyHeaders { + /** + * @member {string} [requestId] This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + */ + requestId?: string; + /** + * @member {string} [version] Indicates the version of the File service used + * to execute the request. + */ + version?: string; + /** + * @member {Date} [date] A UTC date/time value generated by the service that + * indicates the time at which the response was initiated. + */ + date?: Date; + /** + * @member {string} [errorCode] + */ + errorCode?: string; +} + +/** + * Defines values for DeleteSnapshotsOptionType. + * Possible values include: 'include' + * @readonly + * @enum {string} + */ +export enum DeleteSnapshotsOptionType { + Include = 'include', +} + +/** + * Defines values for ListSharesIncludeType. + * Possible values include: 'snapshots', 'metadata' + * @readonly + * @enum {string} + */ +export enum ListSharesIncludeType { + Snapshots = 'snapshots', + Metadata = 'metadata', +} + +/** + * Defines values for CopyStatusType. + * Possible values include: 'pending', 'success', 'aborted', 'failed' + * @readonly + * @enum {string} + */ +export enum CopyStatusType { + Pending = 'pending', + Success = 'success', + Aborted = 'aborted', + Failed = 'failed', +} + +/** + * Defines values for FileRangeWriteType. + * Possible values include: 'update', 'clear' + * @readonly + * @enum {string} + */ +export enum FileRangeWriteType { + Update = 'update', + Clear = 'clear', +} + +/** + * Defines values for FileType. + * Possible values include: 'File' + * There could be more values for this enum apart from the ones defined here.If + * you want to set a value that is not from the known values then you can do + * the following: + * let param: FileType = "someUnknownValueThatWillStillBeValid"; + * @readonly + * @enum {string} + */ +export enum FileType { + File = 'File', +} + +/** + * Contains response data for the setProperties operation. + */ +export type ServiceSetPropertiesResponse = ServiceSetPropertiesHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ServiceSetPropertiesHeaders; + }; +}; + +/** + * Contains response data for the getProperties operation. + */ +export type ServiceGetPropertiesResponse = StorageServiceProperties & ServiceGetPropertiesHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ServiceGetPropertiesHeaders; + /** + * The response body as text (string format) + */ + bodyAsText: string; + /** + * The response body as parsed JSON or XML + */ + parsedBody: StorageServiceProperties; + }; +}; + +/** + * Contains response data for the listSharesSegment operation. + */ +export type ServiceListSharesSegmentResponse = ListSharesResponse & ServiceListSharesSegmentHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ServiceListSharesSegmentHeaders; + /** + * The response body as text (string format) + */ + bodyAsText: string; + /** + * The response body as parsed JSON or XML + */ + parsedBody: ListSharesResponse; + }; +}; + +/** + * Contains response data for the create operation. + */ +export type ShareCreateResponse = ShareCreateHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ShareCreateHeaders; + }; +}; + +/** + * Contains response data for the getProperties operation. + */ +export type ShareGetPropertiesResponse = ShareGetPropertiesHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ShareGetPropertiesHeaders; + }; +}; + +/** + * Contains response data for the deleteMethod operation. + */ +export type ShareDeleteResponse = ShareDeleteHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ShareDeleteHeaders; + }; +}; + +/** + * Contains response data for the createSnapshot operation. + */ +export type ShareCreateSnapshotResponse = ShareCreateSnapshotHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ShareCreateSnapshotHeaders; + }; +}; + +/** + * Contains response data for the setQuota operation. + */ +export type ShareSetQuotaResponse = ShareSetQuotaHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ShareSetQuotaHeaders; + }; +}; + +/** + * Contains response data for the setMetadata operation. + */ +export type ShareSetMetadataResponse = ShareSetMetadataHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ShareSetMetadataHeaders; + }; +}; + +/** + * Contains response data for the getAccessPolicy operation. + */ +export type ShareGetAccessPolicyResponse = Array & ShareGetAccessPolicyHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ShareGetAccessPolicyHeaders; + /** + * The response body as text (string format) + */ + bodyAsText: string; + /** + * The response body as parsed JSON or XML + */ + parsedBody: SignedIdentifier[]; + }; +}; + +/** + * Contains response data for the setAccessPolicy operation. + */ +export type ShareSetAccessPolicyResponse = ShareSetAccessPolicyHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ShareSetAccessPolicyHeaders; + }; +}; + +/** + * Contains response data for the getStatistics operation. + */ +export type ShareGetStatisticsResponse = ShareStats & ShareGetStatisticsHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: ShareGetStatisticsHeaders; + /** + * The response body as text (string format) + */ + bodyAsText: string; + /** + * The response body as parsed JSON or XML + */ + parsedBody: ShareStats; + }; +}; + +/** + * Contains response data for the create operation. + */ +export type DirectoryCreateResponse = DirectoryCreateHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: DirectoryCreateHeaders; + }; +}; + +/** + * Contains response data for the getProperties operation. + */ +export type DirectoryGetPropertiesResponse = DirectoryGetPropertiesHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: DirectoryGetPropertiesHeaders; + }; +}; + +/** + * Contains response data for the deleteMethod operation. + */ +export type DirectoryDeleteResponse = DirectoryDeleteHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: DirectoryDeleteHeaders; + }; +}; + +/** + * Contains response data for the setMetadata operation. + */ +export type DirectorySetMetadataResponse = DirectorySetMetadataHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: DirectorySetMetadataHeaders; + }; +}; + +/** + * Contains response data for the listFilesAndDirectoriesSegment operation. + */ +export type DirectoryListFilesAndDirectoriesSegmentResponse = ListFilesAndDirectoriesSegmentResponse & DirectoryListFilesAndDirectoriesSegmentHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: DirectoryListFilesAndDirectoriesSegmentHeaders; + /** + * The response body as text (string format) + */ + bodyAsText: string; + /** + * The response body as parsed JSON or XML + */ + parsedBody: ListFilesAndDirectoriesSegmentResponse; + }; +}; + +/** + * Contains response data for the create operation. + */ +export type FileCreateResponse = FileCreateHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileCreateHeaders; + }; +}; + +/** + * Contains response data for the download operation. + */ +export type FileDownloadResponse = FileDownloadHeaders & { + /** + * BROWSER ONLY + * + * The response body as a browser Blob. + * Always undefined in node.js. + */ + blobBody?: Promise; + /** + * NODEJS ONLY + * + * The response body as a node.js Readable stream. + * Always undefined in the browser. + */ + readableStreamBody?: NodeJS.ReadableStream; + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileDownloadHeaders; + }; +}; + +/** + * Contains response data for the getProperties operation. + */ +export type FileGetPropertiesResponse = FileGetPropertiesHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileGetPropertiesHeaders; + }; +}; + +/** + * Contains response data for the deleteMethod operation. + */ +export type FileDeleteResponse = FileDeleteHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileDeleteHeaders; + }; +}; + +/** + * Contains response data for the setHTTPHeaders operation. + */ +export type FileSetHTTPHeadersResponse = FileSetHTTPHeadersHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileSetHTTPHeadersHeaders; + }; +}; + +/** + * Contains response data for the setMetadata operation. + */ +export type FileSetMetadataResponse = FileSetMetadataHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileSetMetadataHeaders; + }; +}; + +/** + * Contains response data for the uploadRange operation. + */ +export type FileUploadRangeResponse = FileUploadRangeHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileUploadRangeHeaders; + }; +}; + +/** + * Contains response data for the getRangeList operation. + */ +export type FileGetRangeListResponse = Array & FileGetRangeListHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileGetRangeListHeaders; + /** + * The response body as text (string format) + */ + bodyAsText: string; + /** + * The response body as parsed JSON or XML + */ + parsedBody: Range[]; + }; +}; + +/** + * Contains response data for the startCopy operation. + */ +export type FileStartCopyResponse = FileStartCopyHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileStartCopyHeaders; + }; +}; + +/** + * Contains response data for the abortCopy operation. + */ +export type FileAbortCopyResponse = FileAbortCopyHeaders & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The parsed HTTP response headers. + */ + parsedHeaders: FileAbortCopyHeaders; + }; +}; diff --git a/file/lib/generated/models/mappers.ts b/file/lib/generated/models/mappers.ts new file mode 100644 index 0000000..d8db71d --- /dev/null +++ b/file/lib/generated/models/mappers.ts @@ -0,0 +1,2079 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "ms-rest-js"; + + +export const AccessPolicy: msRest.CompositeMapper = { + serializedName: "AccessPolicy", + type: { + name: "Composite", + className: "AccessPolicy", + modelProperties: { + start: { + xmlName: "Start", + serializedName: "Start", + type: { + name: "String" + } + }, + expiry: { + xmlName: "Expiry", + serializedName: "Expiry", + type: { + name: "String" + } + }, + permission: { + xmlName: "Permission", + serializedName: "Permission", + type: { + name: "String" + } + } + } + } +}; + +export const CorsRule: msRest.CompositeMapper = { + serializedName: "CorsRule", + type: { + name: "Composite", + className: "CorsRule", + modelProperties: { + allowedOrigins: { + xmlName: "AllowedOrigins", + required: true, + serializedName: "AllowedOrigins", + type: { + name: "String" + } + }, + allowedMethods: { + xmlName: "AllowedMethods", + required: true, + serializedName: "AllowedMethods", + type: { + name: "String" + } + }, + allowedHeaders: { + xmlName: "AllowedHeaders", + required: true, + serializedName: "AllowedHeaders", + type: { + name: "String" + } + }, + exposedHeaders: { + xmlName: "ExposedHeaders", + required: true, + serializedName: "ExposedHeaders", + type: { + name: "String" + } + }, + maxAgeInSeconds: { + xmlName: "MaxAgeInSeconds", + required: true, + serializedName: "MaxAgeInSeconds", + constraints: { + InclusiveMinimum: 0 + }, + type: { + name: "Number" + } + } + } + } +}; + +export const Entry: msRest.CompositeMapper = { + serializedName: "Entry", + type: { + name: "Composite", + polymorphicDiscriminator: { + serializedName: "EntryType", + clientName: "entryType" + }, + uberParent: "Entry", + className: "Entry", + modelProperties: { + name: { + xmlName: "Name", + required: true, + serializedName: "Name", + type: { + name: "String" + } + }, + entryType: { + xmlName: "entryType", + required: true, + serializedName: "EntryType", + type: { + name: "String" + } + } + } + } +}; + +export const DirectoryItem: msRest.CompositeMapper = { + serializedName: "Directory", + type: { + name: "Composite", + className: "DirectoryItem", + modelProperties: { + ...Entry.type.modelProperties + } + } +}; + +export const FileProperty: msRest.CompositeMapper = { + serializedName: "FileProperty", + type: { + name: "Composite", + className: "FileProperty", + modelProperties: { + contentLength: { + xmlName: "Content-Length", + required: true, + serializedName: "Content-Length", + type: { + name: "Number" + } + } + } + } +}; + +export const FileItem: msRest.CompositeMapper = { + serializedName: "File", + type: { + name: "Composite", + className: "FileItem", + modelProperties: { + ...Entry.type.modelProperties, + properties: { + xmlName: "Properties", + required: true, + serializedName: "Properties", + type: { + name: "Composite", + className: "FileProperty" + } + } + } + } +}; + +export const ListFilesAndDirectoriesSegmentResponse: msRest.CompositeMapper = { + xmlName: "EnumerationResults", + serializedName: "ListFilesAndDirectoriesSegmentResponse", + type: { + name: "Composite", + className: "ListFilesAndDirectoriesSegmentResponse", + modelProperties: { + serviceEndpoint: { + xmlIsAttribute: true, + xmlName: "ServiceEndpoint", + required: true, + serializedName: "ServiceEndpoint", + type: { + name: "String" + } + }, + shareName: { + xmlIsAttribute: true, + xmlName: "ShareName", + required: true, + serializedName: "ShareName", + type: { + name: "String" + } + }, + shareSnapshot: { + xmlIsAttribute: true, + xmlName: "ShareSnapshot", + serializedName: "ShareSnapshot", + type: { + name: "String" + } + }, + directoryPath: { + xmlIsAttribute: true, + xmlName: "DirectoryPath", + required: true, + serializedName: "DirectoryPath", + type: { + name: "String" + } + }, + prefix: { + xmlName: "Prefix", + required: true, + serializedName: "Prefix", + type: { + name: "String" + } + }, + marker: { + xmlName: "Marker", + serializedName: "Marker", + type: { + name: "String" + } + }, + maxResults: { + xmlName: "MaxResults", + serializedName: "MaxResults", + type: { + name: "Number" + } + }, + entries: { + xmlIsWrapped: true, + xmlName: "Entries", + xmlElementName: "Entry", + serializedName: "Entries", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + polymorphicDiscriminator: { + serializedName: "EntryType", + clientName: "entryType" + }, + uberParent: "Entry", + className: "Entry" + } + } + } + }, + nextMarker: { + xmlName: "NextMarker", + required: true, + serializedName: "NextMarker", + type: { + name: "String" + } + } + } + } +}; + +export const ShareProperties: msRest.CompositeMapper = { + serializedName: "ShareProperties", + type: { + name: "Composite", + className: "ShareProperties", + modelProperties: { + lastModified: { + xmlName: "Last-Modified", + required: true, + serializedName: "Last-Modified", + type: { + name: "DateTimeRfc1123" + } + }, + etag: { + xmlName: "Etag", + required: true, + serializedName: "Etag", + type: { + name: "String" + } + }, + quota: { + xmlName: "Quota", + required: true, + serializedName: "Quota", + type: { + name: "Number" + } + } + } + } +}; + +export const ShareItem: msRest.CompositeMapper = { + xmlName: "Share", + serializedName: "ShareItem", + type: { + name: "Composite", + className: "ShareItem", + modelProperties: { + name: { + xmlName: "Name", + required: true, + serializedName: "Name", + type: { + name: "String" + } + }, + snapshot: { + xmlName: "Snapshot", + serializedName: "Snapshot", + type: { + name: "String" + } + }, + properties: { + xmlName: "Properties", + required: true, + serializedName: "Properties", + type: { + name: "Composite", + className: "ShareProperties" + } + }, + metadata: { + xmlName: "Metadata", + serializedName: "Metadata", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + } + } + } + } +}; + +export const ListSharesResponse: msRest.CompositeMapper = { + xmlName: "EnumerationResults", + serializedName: "ListSharesResponse", + type: { + name: "Composite", + className: "ListSharesResponse", + modelProperties: { + serviceEndpoint: { + xmlIsAttribute: true, + xmlName: "ServiceEndpoint", + required: true, + serializedName: "ServiceEndpoint", + type: { + name: "String" + } + }, + prefix: { + xmlName: "Prefix", + serializedName: "Prefix", + type: { + name: "String" + } + }, + marker: { + xmlName: "Marker", + serializedName: "Marker", + type: { + name: "String" + } + }, + maxResults: { + xmlName: "MaxResults", + serializedName: "MaxResults", + type: { + name: "Number" + } + }, + shareItems: { + xmlIsWrapped: true, + xmlName: "Shares", + xmlElementName: "Share", + serializedName: "ShareItems", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "ShareItem" + } + } + } + }, + nextMarker: { + xmlName: "NextMarker", + required: true, + serializedName: "NextMarker", + type: { + name: "String" + } + } + } + } +}; + +export const RetentionPolicy: msRest.CompositeMapper = { + serializedName: "RetentionPolicy", + type: { + name: "Composite", + className: "RetentionPolicy", + modelProperties: { + enabled: { + xmlName: "Enabled", + required: true, + serializedName: "Enabled", + type: { + name: "Boolean" + } + }, + days: { + xmlName: "Days", + serializedName: "Days", + constraints: { + InclusiveMaximum: 365, + InclusiveMinimum: 1 + }, + type: { + name: "Number" + } + } + } + } +}; + +export const Metrics: msRest.CompositeMapper = { + serializedName: "Metrics", + type: { + name: "Composite", + className: "Metrics", + modelProperties: { + version: { + xmlName: "Version", + required: true, + serializedName: "Version", + type: { + name: "String" + } + }, + enabled: { + xmlName: "Enabled", + required: true, + serializedName: "Enabled", + type: { + name: "Boolean" + } + }, + includeAPIs: { + xmlName: "IncludeAPIs", + serializedName: "IncludeAPIs", + type: { + name: "Boolean" + } + }, + retentionPolicy: { + xmlName: "RetentionPolicy", + serializedName: "RetentionPolicy", + type: { + name: "Composite", + className: "RetentionPolicy" + } + } + } + } +}; + +export const Range: msRest.CompositeMapper = { + serializedName: "Range", + type: { + name: "Composite", + className: "Range", + modelProperties: { + start: { + xmlName: "Start", + required: true, + serializedName: "Start", + type: { + name: "Number" + } + }, + end: { + xmlName: "End", + required: true, + serializedName: "End", + type: { + name: "Number" + } + } + } + } +}; + +export const StorageError: msRest.CompositeMapper = { + serializedName: "StorageError", + type: { + name: "Composite", + className: "StorageError", + modelProperties: { + message: { + xmlName: "Message", + serializedName: "Message", + type: { + name: "String" + } + } + } + } +}; + +export const ShareStats: msRest.CompositeMapper = { + serializedName: "ShareStats", + type: { + name: "Composite", + className: "ShareStats", + modelProperties: { + shareUsage: { + xmlName: "ShareUsage", + required: true, + serializedName: "ShareUsage", + type: { + name: "Number" + } + } + } + } +}; + +export const SignedIdentifier: msRest.CompositeMapper = { + serializedName: "SignedIdentifier", + type: { + name: "Composite", + className: "SignedIdentifier", + modelProperties: { + id: { + xmlName: "Id", + required: true, + serializedName: "Id", + type: { + name: "String" + } + }, + accessPolicy: { + xmlName: "AccessPolicy", + serializedName: "AccessPolicy", + type: { + name: "Composite", + className: "AccessPolicy" + } + } + } + } +}; + +export const StorageServiceProperties: msRest.CompositeMapper = { + serializedName: "StorageServiceProperties", + type: { + name: "Composite", + className: "StorageServiceProperties", + modelProperties: { + hourMetrics: { + xmlName: "HourMetrics", + serializedName: "HourMetrics", + type: { + name: "Composite", + className: "Metrics" + } + }, + minuteMetrics: { + xmlName: "MinuteMetrics", + serializedName: "MinuteMetrics", + type: { + name: "Composite", + className: "Metrics" + } + }, + cors: { + xmlIsWrapped: true, + xmlName: "Cors", + xmlElementName: "CorsRule", + serializedName: "Cors", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "CorsRule" + } + } + } + } + } + } +}; + +export const ServiceSetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "service-setproperties-headers", + type: { + name: "Composite", + className: "ServiceSetPropertiesHeaders", + modelProperties: { + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceGetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "service-getproperties-headers", + type: { + name: "Composite", + className: "ServiceGetPropertiesHeaders", + modelProperties: { + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ServiceListSharesSegmentHeaders: msRest.CompositeMapper = { + serializedName: "service-listsharessegment-headers", + type: { + name: "Composite", + className: "ServiceListSharesSegmentHeaders", + modelProperties: { + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ShareCreateHeaders: msRest.CompositeMapper = { + serializedName: "share-create-headers", + type: { + name: "Composite", + className: "ShareCreateHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ShareGetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "share-getproperties-headers", + type: { + name: "Composite", + className: "ShareGetPropertiesHeaders", + modelProperties: { + metadata: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + quota: { + serializedName: "x-ms-share-quota", + type: { + name: "Number" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ShareDeleteHeaders: msRest.CompositeMapper = { + serializedName: "share-delete-headers", + type: { + name: "Composite", + className: "ShareDeleteHeaders", + modelProperties: { + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ShareCreateSnapshotHeaders: msRest.CompositeMapper = { + serializedName: "share-createsnapshot-headers", + type: { + name: "Composite", + className: "ShareCreateSnapshotHeaders", + modelProperties: { + snapshot: { + serializedName: "x-ms-snapshot", + type: { + name: "String" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ShareSetQuotaHeaders: msRest.CompositeMapper = { + serializedName: "share-setquota-headers", + type: { + name: "Composite", + className: "ShareSetQuotaHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ShareSetMetadataHeaders: msRest.CompositeMapper = { + serializedName: "share-setmetadata-headers", + type: { + name: "Composite", + className: "ShareSetMetadataHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ShareGetAccessPolicyHeaders: msRest.CompositeMapper = { + serializedName: "share-getaccesspolicy-headers", + type: { + name: "Composite", + className: "ShareGetAccessPolicyHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ShareSetAccessPolicyHeaders: msRest.CompositeMapper = { + serializedName: "share-setaccesspolicy-headers", + type: { + name: "Composite", + className: "ShareSetAccessPolicyHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const ShareGetStatisticsHeaders: msRest.CompositeMapper = { + serializedName: "share-getstatistics-headers", + type: { + name: "Composite", + className: "ShareGetStatisticsHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const DirectoryCreateHeaders: msRest.CompositeMapper = { + serializedName: "directory-create-headers", + type: { + name: "Composite", + className: "DirectoryCreateHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const DirectoryGetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "directory-getproperties-headers", + type: { + name: "Composite", + className: "DirectoryGetPropertiesHeaders", + modelProperties: { + metadata: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const DirectoryDeleteHeaders: msRest.CompositeMapper = { + serializedName: "directory-delete-headers", + type: { + name: "Composite", + className: "DirectoryDeleteHeaders", + modelProperties: { + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const DirectorySetMetadataHeaders: msRest.CompositeMapper = { + serializedName: "directory-setmetadata-headers", + type: { + name: "Composite", + className: "DirectorySetMetadataHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const DirectoryListFilesAndDirectoriesSegmentHeaders: msRest.CompositeMapper = { + serializedName: "directory-listfilesanddirectoriessegment-headers", + type: { + name: "Composite", + className: "DirectoryListFilesAndDirectoriesSegmentHeaders", + modelProperties: { + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileCreateHeaders: msRest.CompositeMapper = { + serializedName: "file-create-headers", + type: { + name: "Composite", + className: "FileCreateHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileDownloadHeaders: msRest.CompositeMapper = { + serializedName: "file-download-headers", + type: { + name: "Composite", + className: "FileDownloadHeaders", + modelProperties: { + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + metadata: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + }, + contentLength: { + serializedName: "content-length", + type: { + name: "Number" + } + }, + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + contentRange: { + serializedName: "content-range", + type: { + name: "String" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + contentEncoding: { + serializedName: "content-encoding", + type: { + name: "String" + } + }, + cacheControl: { + serializedName: "cache-control", + type: { + name: "String" + } + }, + contentDisposition: { + serializedName: "content-disposition", + type: { + name: "String" + } + }, + contentLanguage: { + serializedName: "content-language", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + acceptRanges: { + serializedName: "accept-ranges", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + copyCompletionTime: { + serializedName: "x-ms-copy-completion-time", + type: { + name: "DateTimeRfc1123" + } + }, + copyStatusDescription: { + serializedName: "x-ms-copy-status-description", + type: { + name: "String" + } + }, + copyId: { + serializedName: "x-ms-copy-id", + type: { + name: "String" + } + }, + copyProgress: { + serializedName: "x-ms-copy-progress", + type: { + name: "String" + } + }, + copySource: { + serializedName: "x-ms-copy-source", + type: { + name: "String" + } + }, + copyStatus: { + serializedName: "x-ms-copy-status", + type: { + name: "Enum", + allowedValues: [ + "pending", + "success", + "aborted", + "failed" + ] + } + }, + fileContentMD5: { + serializedName: "x-ms-content-md5", + type: { + name: "ByteArray" + } + }, + isServerEncrypted: { + serializedName: "x-ms-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileGetPropertiesHeaders: msRest.CompositeMapper = { + serializedName: "file-getproperties-headers", + type: { + name: "Composite", + className: "FileGetPropertiesHeaders", + modelProperties: { + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + metadata: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + }, + fileType: { + serializedName: "x-ms-type", + type: { + name: "String" + } + }, + contentLength: { + serializedName: "content-length", + type: { + name: "Number" + } + }, + contentType: { + serializedName: "content-type", + type: { + name: "String" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + contentEncoding: { + serializedName: "content-encoding", + type: { + name: "String" + } + }, + cacheControl: { + serializedName: "cache-control", + type: { + name: "String" + } + }, + contentDisposition: { + serializedName: "content-disposition", + type: { + name: "String" + } + }, + contentLanguage: { + serializedName: "content-language", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + copyCompletionTime: { + serializedName: "x-ms-copy-completion-time", + type: { + name: "DateTimeRfc1123" + } + }, + copyStatusDescription: { + serializedName: "x-ms-copy-status-description", + type: { + name: "String" + } + }, + copyId: { + serializedName: "x-ms-copy-id", + type: { + name: "String" + } + }, + copyProgress: { + serializedName: "x-ms-copy-progress", + type: { + name: "String" + } + }, + copySource: { + serializedName: "x-ms-copy-source", + type: { + name: "String" + } + }, + copyStatus: { + serializedName: "x-ms-copy-status", + type: { + name: "Enum", + allowedValues: [ + "pending", + "success", + "aborted", + "failed" + ] + } + }, + isServerEncrypted: { + serializedName: "x-ms-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileDeleteHeaders: msRest.CompositeMapper = { + serializedName: "file-delete-headers", + type: { + name: "Composite", + className: "FileDeleteHeaders", + modelProperties: { + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileSetHTTPHeadersHeaders: msRest.CompositeMapper = { + serializedName: "file-sethttpheaders-headers", + type: { + name: "Composite", + className: "FileSetHTTPHeadersHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileSetMetadataHeaders: msRest.CompositeMapper = { + serializedName: "file-setmetadata-headers", + type: { + name: "Composite", + className: "FileSetMetadataHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileUploadRangeHeaders: msRest.CompositeMapper = { + serializedName: "file-uploadrange-headers", + type: { + name: "Composite", + className: "FileUploadRangeHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + contentMD5: { + serializedName: "content-md5", + type: { + name: "ByteArray" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + isServerEncrypted: { + serializedName: "x-ms-request-server-encrypted", + type: { + name: "Boolean" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileGetRangeListHeaders: msRest.CompositeMapper = { + serializedName: "file-getrangelist-headers", + type: { + name: "Composite", + className: "FileGetRangeListHeaders", + modelProperties: { + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + fileContentLength: { + serializedName: "x-ms-content-length", + type: { + name: "Number" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileStartCopyHeaders: msRest.CompositeMapper = { + serializedName: "file-startcopy-headers", + type: { + name: "Composite", + className: "FileStartCopyHeaders", + modelProperties: { + eTag: { + serializedName: "etag", + type: { + name: "String" + } + }, + lastModified: { + serializedName: "last-modified", + type: { + name: "DateTimeRfc1123" + } + }, + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + copyId: { + serializedName: "x-ms-copy-id", + type: { + name: "String" + } + }, + copyStatus: { + serializedName: "x-ms-copy-status", + type: { + name: "Enum", + allowedValues: [ + "pending", + "success", + "aborted", + "failed" + ] + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const FileAbortCopyHeaders: msRest.CompositeMapper = { + serializedName: "file-abortcopy-headers", + type: { + name: "Composite", + className: "FileAbortCopyHeaders", + modelProperties: { + requestId: { + serializedName: "x-ms-request-id", + type: { + name: "String" + } + }, + version: { + serializedName: "x-ms-version", + type: { + name: "String" + } + }, + date: { + serializedName: "date", + type: { + name: "DateTimeRfc1123" + } + }, + errorCode: { + serializedName: "x-ms-error-code", + type: { + name: "String" + } + } + } + } +}; + +export const discriminators = { + 'Entry' : Entry, + 'Entry.Directory' : DirectoryItem, + 'Entry.File' : FileItem +}; diff --git a/file/lib/generated/models/parameters.ts b/file/lib/generated/models/parameters.ts new file mode 100644 index 0000000..bf8e3ba --- /dev/null +++ b/file/lib/generated/models/parameters.ts @@ -0,0 +1,523 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "ms-rest-js"; + +export const comp0: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'properties', + type: { + name: "String" + } + } +}; +export const comp1: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'list', + type: { + name: "String" + } + } +}; +export const comp2: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'snapshot', + type: { + name: "String" + } + } +}; +export const comp3: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'metadata', + type: { + name: "String" + } + } +}; +export const comp4: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'acl', + type: { + name: "String" + } + } +}; +export const comp5: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'stats', + type: { + name: "String" + } + } +}; +export const comp6: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'range', + type: { + name: "String" + } + } +}; +export const comp7: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'rangelist', + type: { + name: "String" + } + } +}; +export const comp8: msRest.OperationQueryParameter = { + parameterPath: "comp", + mapper: { + required: true, + isConstant: true, + serializedName: "comp", + defaultValue: 'copy', + type: { + name: "String" + } + } +}; +export const contentLength: msRest.OperationParameter = { + parameterPath: "contentLength", + mapper: { + required: true, + serializedName: "Content-Length", + type: { + name: "Number" + } + } +}; +export const contentMD5: msRest.OperationParameter = { + parameterPath: [ + "options", + "contentMD5" + ], + mapper: { + serializedName: "Content-MD5", + type: { + name: "ByteArray" + } + } +}; +export const copyActionAbortConstant: msRest.OperationParameter = { + parameterPath: "copyActionAbortConstant", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-copy-action", + defaultValue: 'abort', + type: { + name: "String" + } + } +}; +export const copyId: msRest.OperationQueryParameter = { + parameterPath: "copyId", + mapper: { + required: true, + serializedName: "copyid", + type: { + name: "String" + } + } +}; +export const copySource: msRest.OperationParameter = { + parameterPath: "copySource", + mapper: { + required: true, + serializedName: "x-ms-copy-source", + type: { + name: "String" + } + } +}; +export const deleteSnapshots: msRest.OperationParameter = { + parameterPath: [ + "options", + "deleteSnapshots" + ], + mapper: { + serializedName: "x-ms-delete-snapshots", + type: { + name: "Enum", + allowedValues: [ + "include" + ] + } + } +}; +export const fileCacheControl: msRest.OperationParameter = { + parameterPath: [ + "options", + "fileCacheControl" + ], + mapper: { + serializedName: "x-ms-cache-control", + type: { + name: "String" + } + } +}; +export const fileContentDisposition: msRest.OperationParameter = { + parameterPath: [ + "options", + "fileContentDisposition" + ], + mapper: { + serializedName: "x-ms-content-disposition", + type: { + name: "String" + } + } +}; +export const fileContentEncoding: msRest.OperationParameter = { + parameterPath: [ + "options", + "fileContentEncoding" + ], + mapper: { + serializedName: "x-ms-content-encoding", + type: { + name: "String" + } + } +}; +export const fileContentLanguage: msRest.OperationParameter = { + parameterPath: [ + "options", + "fileContentLanguage" + ], + mapper: { + serializedName: "x-ms-content-language", + type: { + name: "String" + } + } +}; +export const fileContentLength0: msRest.OperationParameter = { + parameterPath: "fileContentLength", + mapper: { + required: true, + serializedName: "x-ms-content-length", + type: { + name: "Number" + } + } +}; +export const fileContentLength1: msRest.OperationParameter = { + parameterPath: [ + "options", + "fileContentLength" + ], + mapper: { + serializedName: "x-ms-content-length", + type: { + name: "Number" + } + } +}; +export const fileContentMD5: msRest.OperationParameter = { + parameterPath: [ + "options", + "fileContentMD5" + ], + mapper: { + serializedName: "x-ms-content-md5", + type: { + name: "ByteArray" + } + } +}; +export const fileContentType: msRest.OperationParameter = { + parameterPath: [ + "options", + "fileContentType" + ], + mapper: { + serializedName: "x-ms-content-type", + type: { + name: "String" + } + } +}; +export const fileRangeWrite: msRest.OperationParameter = { + parameterPath: "fileRangeWrite", + mapper: { + required: true, + serializedName: "x-ms-write", + defaultValue: 'update', + type: { + name: "Enum", + allowedValues: [ + "update", + "clear" + ] + } + } +}; +export const fileTypeConstant: msRest.OperationParameter = { + parameterPath: "fileTypeConstant", + mapper: { + required: true, + isConstant: true, + serializedName: "x-ms-type", + defaultValue: 'file', + type: { + name: "String" + } + } +}; +export const include: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "include" + ], + mapper: { + serializedName: "include", + type: { + name: "Sequence", + element: { + type: { + name: "Enum", + allowedValues: [ + "snapshots", + "metadata" + ] + } + } + } + }, + collectionFormat: msRest.QueryCollectionFormat.Csv +}; +export const marker: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "marker" + ], + mapper: { + serializedName: "marker", + type: { + name: "String" + } + } +}; +export const maxresults: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "maxresults" + ], + mapper: { + serializedName: "maxresults", + constraints: { + InclusiveMinimum: 1 + }, + type: { + name: "Number" + } + } +}; +export const metadata: msRest.OperationParameter = { + parameterPath: [ + "options", + "metadata" + ], + mapper: { + serializedName: "x-ms-meta", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + }, + headerCollectionPrefix: "x-ms-meta-" + } +}; +export const prefix: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "prefix" + ], + mapper: { + serializedName: "prefix", + type: { + name: "String" + } + } +}; +export const quota: msRest.OperationParameter = { + parameterPath: [ + "options", + "quota" + ], + mapper: { + serializedName: "x-ms-share-quota", + constraints: { + InclusiveMinimum: 1 + }, + type: { + name: "Number" + } + } +}; +export const range0: msRest.OperationParameter = { + parameterPath: [ + "options", + "range" + ], + mapper: { + serializedName: "x-ms-range", + type: { + name: "String" + } + } +}; +export const range1: msRest.OperationParameter = { + parameterPath: "range", + mapper: { + required: true, + serializedName: "x-ms-range", + type: { + name: "String" + } + } +}; +export const rangeGetContentMD5: msRest.OperationParameter = { + parameterPath: [ + "options", + "rangeGetContentMD5" + ], + mapper: { + serializedName: "x-ms-range-get-content-md5", + type: { + name: "Boolean" + } + } +}; +export const restype0: msRest.OperationQueryParameter = { + parameterPath: "restype", + mapper: { + required: true, + isConstant: true, + serializedName: "restype", + defaultValue: 'service', + type: { + name: "String" + } + } +}; +export const restype1: msRest.OperationQueryParameter = { + parameterPath: "restype", + mapper: { + required: true, + isConstant: true, + serializedName: "restype", + defaultValue: 'share', + type: { + name: "String" + } + } +}; +export const restype2: msRest.OperationQueryParameter = { + parameterPath: "restype", + mapper: { + required: true, + isConstant: true, + serializedName: "restype", + defaultValue: 'directory', + type: { + name: "String" + } + } +}; +export const sharesnapshot: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "sharesnapshot" + ], + mapper: { + serializedName: "sharesnapshot", + type: { + name: "String" + } + } +}; +export const timeout: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "timeout" + ], + mapper: { + serializedName: "timeout", + constraints: { + InclusiveMinimum: 0 + }, + type: { + name: "Number" + } + } +}; +export const url: msRest.OperationURLParameter = { + parameterPath: "url", + mapper: { + required: true, + serializedName: "url", + defaultValue: '', + type: { + name: "String" + } + }, + skipEncoding: true +}; +export const version: msRest.OperationParameter = { + parameterPath: "version", + mapper: { + required: true, + serializedName: "x-ms-version", + type: { + name: "String" + } + } +}; diff --git a/file/lib/generated/models/serviceMappers.ts b/file/lib/generated/models/serviceMappers.ts new file mode 100644 index 0000000..86e757a --- /dev/null +++ b/file/lib/generated/models/serviceMappers.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +export { + discriminators, + StorageServiceProperties, + Metrics, + RetentionPolicy, + CorsRule, + ServiceSetPropertiesHeaders, + StorageError, + ServiceGetPropertiesHeaders, + ListSharesResponse, + ShareItem, + ShareProperties, + ServiceListSharesSegmentHeaders +} from "../models/mappers"; + diff --git a/file/lib/generated/models/shareMappers.ts b/file/lib/generated/models/shareMappers.ts new file mode 100644 index 0000000..412e3d4 --- /dev/null +++ b/file/lib/generated/models/shareMappers.ts @@ -0,0 +1,27 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +export { + discriminators, + ShareCreateHeaders, + StorageError, + ShareGetPropertiesHeaders, + ShareDeleteHeaders, + ShareCreateSnapshotHeaders, + ShareSetQuotaHeaders, + ShareSetMetadataHeaders, + SignedIdentifier, + AccessPolicy, + ShareGetAccessPolicyHeaders, + ShareSetAccessPolicyHeaders, + ShareStats, + ShareGetStatisticsHeaders +} from "../models/mappers"; + diff --git a/file/lib/generated/operations/directory.ts b/file/lib/generated/operations/directory.ts new file mode 100644 index 0000000..4ec8aeb --- /dev/null +++ b/file/lib/generated/operations/directory.ts @@ -0,0 +1,290 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/directoryMappers"; +import * as Parameters from "../models/parameters"; +import { StorageClientContext } from "../storageClientContext"; + +/** Class representing a Directory. */ +export class Directory { + private readonly client: StorageClientContext; + + /** + * Create a Directory. + * @param {StorageClientContext} client Reference to the service client. + */ + constructor(client: StorageClientContext) { + this.client = client; + } + + /** + * Creates a new directory under the specified share or parent directory. + * + * @param {DirectoryCreateOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + create(): Promise; + create(options: Models.DirectoryCreateOptionalParams): Promise; + create(callback: msRest.ServiceCallback): void; + create(options: Models.DirectoryCreateOptionalParams, callback: msRest.ServiceCallback): void; + create(options?: Models.DirectoryCreateOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + createOperationSpec, + callback) as Promise; + } + + /** + * Returns all system properties for the specified directory, and can also be used to check the + * existence of a directory. The data returned does not include the files in the directory or any + * subdirectories. + * + * @param {DirectoryGetPropertiesOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + getProperties(): Promise; + getProperties(options: Models.DirectoryGetPropertiesOptionalParams): Promise; + getProperties(callback: msRest.ServiceCallback): void; + getProperties(options: Models.DirectoryGetPropertiesOptionalParams, callback: msRest.ServiceCallback): void; + getProperties(options?: Models.DirectoryGetPropertiesOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + getPropertiesOperationSpec, + callback) as Promise; + } + + /** + * Removes the specified empty directory. Note that the directory must be empty before it can be + * deleted. + * + * @param {DirectoryDeleteMethodOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + deleteMethod(): Promise; + deleteMethod(options: Models.DirectoryDeleteMethodOptionalParams): Promise; + deleteMethod(callback: msRest.ServiceCallback): void; + deleteMethod(options: Models.DirectoryDeleteMethodOptionalParams, callback: msRest.ServiceCallback): void; + deleteMethod(options?: Models.DirectoryDeleteMethodOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + deleteMethodOperationSpec, + callback) as Promise; + } + + /** + * Updates user defined metadata for the specified directory. + * + * @param {DirectorySetMetadataOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + setMetadata(): Promise; + setMetadata(options: Models.DirectorySetMetadataOptionalParams): Promise; + setMetadata(callback: msRest.ServiceCallback): void; + setMetadata(options: Models.DirectorySetMetadataOptionalParams, callback: msRest.ServiceCallback): void; + setMetadata(options?: Models.DirectorySetMetadataOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + setMetadataOperationSpec, + callback) as Promise; + } + + /** + * Returns a list of files or directories under the specified share or directory. It lists the + * contents only for a single level of the directory hierarchy. + * + * @param {DirectoryListFilesAndDirectoriesSegmentOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + listFilesAndDirectoriesSegment(): Promise; + listFilesAndDirectoriesSegment(options: Models.DirectoryListFilesAndDirectoriesSegmentOptionalParams): Promise; + listFilesAndDirectoriesSegment(callback: msRest.ServiceCallback): void; + listFilesAndDirectoriesSegment(options: Models.DirectoryListFilesAndDirectoriesSegmentOptionalParams, callback: msRest.ServiceCallback): void; + listFilesAndDirectoriesSegment(options?: Models.DirectoryListFilesAndDirectoriesSegmentOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + listFilesAndDirectoriesSegmentOperationSpec, + callback) as Promise; + } + +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers, true); +const createOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}/{directory}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2 + ], + headerParameters: [ + Parameters.metadata, + Parameters.version + ], + responses: { + 201: { + headersMapper: Mappers.DirectoryCreateHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const getPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{shareName}/{directory}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.sharesnapshot, + Parameters.timeout, + Parameters.restype2 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.DirectoryGetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const deleteMethodOperationSpec: msRest.OperationSpec = { + httpMethod: "DELETE", + path: "{shareName}/{directory}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 202: { + headersMapper: Mappers.DirectoryDeleteHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const setMetadataOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}/{directory}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype2, + Parameters.comp3 + ], + headerParameters: [ + Parameters.metadata, + Parameters.version + ], + responses: { + 202: { + headersMapper: Mappers.DirectorySetMetadataHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const listFilesAndDirectoriesSegmentOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{shareName}/{directory}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.prefix, + Parameters.sharesnapshot, + Parameters.marker, + Parameters.maxresults, + Parameters.timeout, + Parameters.restype2, + Parameters.comp1 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + bodyMapper: Mappers.ListFilesAndDirectoriesSegmentResponse, + headersMapper: Mappers.DirectoryListFilesAndDirectoriesSegmentHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; diff --git a/file/lib/generated/operations/file.ts b/file/lib/generated/operations/file.ts new file mode 100644 index 0000000..46e7649 --- /dev/null +++ b/file/lib/generated/operations/file.ts @@ -0,0 +1,624 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/fileMappers"; +import * as Parameters from "../models/parameters"; +import { StorageClientContext } from "../storageClientContext"; + +/** Class representing a File. */ +export class File { + private readonly client: StorageClientContext; + + /** + * Create a File. + * @param {StorageClientContext} client Reference to the service client. + */ + constructor(client: StorageClientContext) { + this.client = client; + } + + /** + * Creates a new file or replaces a file. Note it only initializes the file with no content. + * + * @param {number} fileContentLength Specifies the maximum size for the file, up to 1 TB. + * + * @param {FileCreateOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + create(fileContentLength: number): Promise; + create(fileContentLength: number, options: Models.FileCreateOptionalParams): Promise; + create(fileContentLength: number, callback: msRest.ServiceCallback): void; + create(fileContentLength: number, options: Models.FileCreateOptionalParams, callback: msRest.ServiceCallback): void; + create(fileContentLength: number, options?: Models.FileCreateOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + fileContentLength, + options + }, + createOperationSpec, + callback) as Promise; + } + + /** + * Reads or downloads a file from the system, including its metadata and properties. + * + * @param {FileDownloadOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + download(): Promise; + download(options: Models.FileDownloadOptionalParams): Promise; + download(callback: msRest.ServiceCallback): void; + download(options: Models.FileDownloadOptionalParams, callback: msRest.ServiceCallback): void; + download(options?: Models.FileDownloadOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + downloadOperationSpec, + callback) as Promise; + } + + /** + * Returns all user-defined metadata, standard HTTP properties, and system properties for the file. + * It does not return the content of the file. + * + * @param {FileGetPropertiesOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + getProperties(): Promise; + getProperties(options: Models.FileGetPropertiesOptionalParams): Promise; + getProperties(callback: msRest.ServiceCallback): void; + getProperties(options: Models.FileGetPropertiesOptionalParams, callback: msRest.ServiceCallback): void; + getProperties(options?: Models.FileGetPropertiesOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + getPropertiesOperationSpec, + callback) as Promise; + } + + /** + * removes the file from the storage account. + * + * @param {FileDeleteMethodOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + deleteMethod(): Promise; + deleteMethod(options: Models.FileDeleteMethodOptionalParams): Promise; + deleteMethod(callback: msRest.ServiceCallback): void; + deleteMethod(options: Models.FileDeleteMethodOptionalParams, callback: msRest.ServiceCallback): void; + deleteMethod(options?: Models.FileDeleteMethodOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + deleteMethodOperationSpec, + callback) as Promise; + } + + /** + * Sets HTTP headers on the file. + * + * @param {FileSetHTTPHeadersOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + setHTTPHeaders(): Promise; + setHTTPHeaders(options: Models.FileSetHTTPHeadersOptionalParams): Promise; + setHTTPHeaders(callback: msRest.ServiceCallback): void; + setHTTPHeaders(options: Models.FileSetHTTPHeadersOptionalParams, callback: msRest.ServiceCallback): void; + setHTTPHeaders(options?: Models.FileSetHTTPHeadersOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + setHTTPHeadersOperationSpec, + callback) as Promise; + } + + /** + * Updates user-defined metadata for the specified file. + * + * @param {FileSetMetadataOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + setMetadata(): Promise; + setMetadata(options: Models.FileSetMetadataOptionalParams): Promise; + setMetadata(callback: msRest.ServiceCallback): void; + setMetadata(options: Models.FileSetMetadataOptionalParams, callback: msRest.ServiceCallback): void; + setMetadata(options?: Models.FileSetMetadataOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + setMetadataOperationSpec, + callback) as Promise; + } + + /** + * Upload a range of bytes to a file. + * + * @param {string} range Specifies the range of bytes to be written. Both the start and end of the + * range must be specified. For an update operation, the range can be up to 4 MB in size. For a + * clear operation, the range can be up to the value of the file's full size. The File service + * accepts only a single byte range for the Range and 'x-ms-range' headers, and the byte range must + * be specified in the following format: bytes=startByte-endByte. + * + * @param {FileRangeWriteType} fileRangeWrite Specify one of the following options: - Update: + * Writes the bytes specified by the request body into the specified range. The Range and + * Content-Length headers must match to perform the update. - Clear: Clears the specified range and + * releases the space used in storage for that range. To clear a range, set the Content-Length + * header to zero, and set the Range header to a value that indicates the range to clear, up to + * maximum file size. Possible values include: 'update', 'clear' + * + * @param {number} contentLength Specifies the number of bytes being transmitted in the request + * body. When the x-ms-write header is set to clear, the value of this header must be set to zero. + * + * @param {FileUploadRangeOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + uploadRange(range: string, fileRangeWrite: Models.FileRangeWriteType, contentLength: number): Promise; + uploadRange(range: string, fileRangeWrite: Models.FileRangeWriteType, contentLength: number, options: Models.FileUploadRangeOptionalParams): Promise; + uploadRange(range: string, fileRangeWrite: Models.FileRangeWriteType, contentLength: number, callback: msRest.ServiceCallback): void; + uploadRange(range: string, fileRangeWrite: Models.FileRangeWriteType, contentLength: number, options: Models.FileUploadRangeOptionalParams, callback: msRest.ServiceCallback): void; + uploadRange(range: string, fileRangeWrite: Models.FileRangeWriteType, contentLength: number, options?: Models.FileUploadRangeOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + range, + fileRangeWrite, + contentLength, + options + }, + uploadRangeOperationSpec, + callback) as Promise; + } + + /** + * Returns the list of valid ranges for a file. + * + * @param {FileGetRangeListOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + getRangeList(): Promise; + getRangeList(options: Models.FileGetRangeListOptionalParams): Promise; + getRangeList(callback: msRest.ServiceCallback): void; + getRangeList(options: Models.FileGetRangeListOptionalParams, callback: msRest.ServiceCallback): void; + getRangeList(options?: Models.FileGetRangeListOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + getRangeListOperationSpec, + callback) as Promise; + } + + /** + * Copies a blob or file to a destination file within the storage account. + * + * @param {string} copySource Specifies the URL of the source file or blob, up to 2 KB in length. + * To copy a file to another file within the same storage account, you may use Shared Key to + * authenticate the source file. If you are copying a file from another storage account, or if you + * are copying a blob from the same storage account or another storage account, then you must + * authenticate the source file or blob using a shared access signature. If the source is a public + * blob, no authentication is required to perform the copy operation. A file in a share snapshot + * can also be specified as a copy source. + * + * @param {FileStartCopyOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + startCopy(copySource: string): Promise; + startCopy(copySource: string, options: Models.FileStartCopyOptionalParams): Promise; + startCopy(copySource: string, callback: msRest.ServiceCallback): void; + startCopy(copySource: string, options: Models.FileStartCopyOptionalParams, callback: msRest.ServiceCallback): void; + startCopy(copySource: string, options?: Models.FileStartCopyOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + copySource, + options + }, + startCopyOperationSpec, + callback) as Promise; + } + + /** + * Aborts a pending Copy File operation, and leaves a destination file with zero length and full + * metadata. + * + * @param {string} copyId The copy identifier provided in the x-ms-copy-id header of the original + * Copy File operation. + * + * @param {FileAbortCopyOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + abortCopy(copyId: string): Promise; + abortCopy(copyId: string, options: Models.FileAbortCopyOptionalParams): Promise; + abortCopy(copyId: string, callback: msRest.ServiceCallback): void; + abortCopy(copyId: string, options: Models.FileAbortCopyOptionalParams, callback: msRest.ServiceCallback): void; + abortCopy(copyId: string, options?: Models.FileAbortCopyOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + copyId, + options + }, + abortCopyOperationSpec, + callback) as Promise; + } + +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers, true); +const createOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.version, + Parameters.fileContentLength0, + Parameters.fileTypeConstant, + Parameters.fileContentType, + Parameters.fileContentEncoding, + Parameters.fileContentLanguage, + Parameters.fileCacheControl, + Parameters.fileContentMD5, + Parameters.fileContentDisposition, + Parameters.metadata + ], + responses: { + 201: { + headersMapper: Mappers.FileCreateHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const downloadOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.version, + Parameters.range0, + Parameters.rangeGetContentMD5 + ], + responses: { + 200: { + bodyMapper: { + serializedName: "parsedResponse", + type: { + name: "Stream" + } + }, + headersMapper: Mappers.FileDownloadHeaders + }, + 206: { + bodyMapper: { + serializedName: "parsedResponse", + type: { + name: "Stream" + } + }, + headersMapper: Mappers.FileDownloadHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const getPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "HEAD", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.sharesnapshot, + Parameters.timeout + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.FileGetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const deleteMethodOperationSpec: msRest.OperationSpec = { + httpMethod: "DELETE", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.version + ], + responses: { + 202: { + headersMapper: Mappers.FileDeleteHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const setHTTPHeadersOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version, + Parameters.fileContentLength1, + Parameters.fileContentType, + Parameters.fileContentEncoding, + Parameters.fileContentLanguage, + Parameters.fileCacheControl, + Parameters.fileContentMD5, + Parameters.fileContentDisposition + ], + responses: { + 200: { + headersMapper: Mappers.FileSetHTTPHeadersHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const setMetadataOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp3 + ], + headerParameters: [ + Parameters.metadata, + Parameters.version + ], + responses: { + 202: { + headersMapper: Mappers.FileSetMetadataHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const uploadRangeOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.comp6 + ], + headerParameters: [ + Parameters.range1, + Parameters.fileRangeWrite, + Parameters.contentLength, + Parameters.contentMD5, + Parameters.version + ], + requestBody: { + parameterPath: [ + "options", + "optionalbody" + ], + mapper: { + serializedName: "optionalbody", + type: { + name: "Stream" + } + } + }, + contentType: "application/octet-stream", + responses: { + 201: { + headersMapper: Mappers.FileUploadRangeHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const getRangeListOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.sharesnapshot, + Parameters.timeout, + Parameters.comp7 + ], + headerParameters: [ + Parameters.version, + Parameters.range0 + ], + responses: { + 200: { + bodyMapper: { + xmlElementName: "Ranges", + serializedName: "parsedResponse", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "Range" + } + } + } + }, + headersMapper: Mappers.FileGetRangeListHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const startCopyOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout + ], + headerParameters: [ + Parameters.version, + Parameters.metadata, + Parameters.copySource + ], + responses: { + 202: { + headersMapper: Mappers.FileStartCopyHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const abortCopyOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}/{directory}/{fileName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.copyId, + Parameters.timeout, + Parameters.comp8 + ], + headerParameters: [ + Parameters.copyActionAbortConstant, + Parameters.version + ], + responses: { + 204: { + headersMapper: Mappers.FileAbortCopyHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; diff --git a/file/lib/generated/operations/index.ts b/file/lib/generated/operations/index.ts new file mode 100644 index 0000000..44ac61a --- /dev/null +++ b/file/lib/generated/operations/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +export * from "./service"; +export * from "./share"; +export * from "./directory"; +export * from "./file"; diff --git a/file/lib/generated/operations/service.ts b/file/lib/generated/operations/service.ts new file mode 100644 index 0000000..5469dcb --- /dev/null +++ b/file/lib/generated/operations/service.ts @@ -0,0 +1,197 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/serviceMappers"; +import * as Parameters from "../models/parameters"; +import { StorageClientContext } from "../storageClientContext"; + +/** Class representing a Service. */ +export class Service { + private readonly client: StorageClientContext; + + /** + * Create a Service. + * @param {StorageClientContext} client Reference to the service client. + */ + constructor(client: StorageClientContext) { + this.client = client; + } + + /** + * Sets properties for a storage account's File service endpoint, including properties for Storage + * Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param {StorageServiceProperties} storageServiceProperties The StorageService properties. + * + * @param {ServiceSetPropertiesOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + setProperties(storageServiceProperties: Models.StorageServiceProperties): Promise; + setProperties(storageServiceProperties: Models.StorageServiceProperties, options: Models.ServiceSetPropertiesOptionalParams): Promise; + setProperties(storageServiceProperties: Models.StorageServiceProperties, callback: msRest.ServiceCallback): void; + setProperties(storageServiceProperties: Models.StorageServiceProperties, options: Models.ServiceSetPropertiesOptionalParams, callback: msRest.ServiceCallback): void; + setProperties(storageServiceProperties: Models.StorageServiceProperties, options?: Models.ServiceSetPropertiesOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + storageServiceProperties, + options + }, + setPropertiesOperationSpec, + callback) as Promise; + } + + /** + * Gets the properties of a storage account's File service, including properties for Storage + * Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param {ServiceGetPropertiesOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + getProperties(): Promise; + getProperties(options: Models.ServiceGetPropertiesOptionalParams): Promise; + getProperties(callback: msRest.ServiceCallback): void; + getProperties(options: Models.ServiceGetPropertiesOptionalParams, callback: msRest.ServiceCallback): void; + getProperties(options?: Models.ServiceGetPropertiesOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + getPropertiesOperationSpec, + callback) as Promise; + } + + /** + * The List Shares Segment operation returns a list of the shares and share snapshots under the + * specified account. + * + * @param {ServiceListSharesSegmentOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + listSharesSegment(): Promise; + listSharesSegment(options: Models.ServiceListSharesSegmentOptionalParams): Promise; + listSharesSegment(callback: msRest.ServiceCallback): void; + listSharesSegment(options: Models.ServiceListSharesSegmentOptionalParams, callback: msRest.ServiceCallback): void; + listSharesSegment(options?: Models.ServiceListSharesSegmentOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + listSharesSegmentOperationSpec, + callback) as Promise; + } + +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers, true); +const setPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype0, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version + ], + requestBody: { + parameterPath: "storageServiceProperties", + mapper: { + ...Mappers.StorageServiceProperties, + required: true + } + }, + contentType: "application/xml; charset=utf-8", + responses: { + 202: { + headersMapper: Mappers.ServiceSetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const getPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype0, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + bodyMapper: Mappers.StorageServiceProperties, + headersMapper: Mappers.ServiceGetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const listSharesSegmentOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.prefix, + Parameters.marker, + Parameters.maxresults, + Parameters.include, + Parameters.timeout, + Parameters.comp1 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + bodyMapper: Mappers.ListSharesResponse, + headersMapper: Mappers.ServiceListSharesSegmentHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; diff --git a/file/lib/generated/operations/share.ts b/file/lib/generated/operations/share.ts new file mode 100644 index 0000000..3668ae4 --- /dev/null +++ b/file/lib/generated/operations/share.ts @@ -0,0 +1,524 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/shareMappers"; +import * as Parameters from "../models/parameters"; +import { StorageClientContext } from "../storageClientContext"; + +/** Class representing a Share. */ +export class Share { + private readonly client: StorageClientContext; + + /** + * Create a Share. + * @param {StorageClientContext} client Reference to the service client. + */ + constructor(client: StorageClientContext) { + this.client = client; + } + + /** + * Creates a new share under the specified account. If the share with the same name already exists, + * the operation fails. + * + * @param {ShareCreateOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + create(): Promise; + create(options: Models.ShareCreateOptionalParams): Promise; + create(callback: msRest.ServiceCallback): void; + create(options: Models.ShareCreateOptionalParams, callback: msRest.ServiceCallback): void; + create(options?: Models.ShareCreateOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + createOperationSpec, + callback) as Promise; + } + + /** + * Returns all user-defined metadata and system properties for the specified share or share + * snapshot. The data returned does not include the share's list of files. + * + * @param {ShareGetPropertiesOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + getProperties(): Promise; + getProperties(options: Models.ShareGetPropertiesOptionalParams): Promise; + getProperties(callback: msRest.ServiceCallback): void; + getProperties(options: Models.ShareGetPropertiesOptionalParams, callback: msRest.ServiceCallback): void; + getProperties(options?: Models.ShareGetPropertiesOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + getPropertiesOperationSpec, + callback) as Promise; + } + + /** + * Operation marks the specified share or share snapshot for deletion. The share or share snapshot + * and any files contained within it are later deleted during garbage collection. + * + * @param {ShareDeleteMethodOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + deleteMethod(): Promise; + deleteMethod(options: Models.ShareDeleteMethodOptionalParams): Promise; + deleteMethod(callback: msRest.ServiceCallback): void; + deleteMethod(options: Models.ShareDeleteMethodOptionalParams, callback: msRest.ServiceCallback): void; + deleteMethod(options?: Models.ShareDeleteMethodOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + deleteMethodOperationSpec, + callback) as Promise; + } + + /** + * Creates a read-only snapshot of a share. + * + * @param {ShareCreateSnapshotOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + createSnapshot(): Promise; + createSnapshot(options: Models.ShareCreateSnapshotOptionalParams): Promise; + createSnapshot(callback: msRest.ServiceCallback): void; + createSnapshot(options: Models.ShareCreateSnapshotOptionalParams, callback: msRest.ServiceCallback): void; + createSnapshot(options?: Models.ShareCreateSnapshotOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + createSnapshotOperationSpec, + callback) as Promise; + } + + /** + * Sets quota for the specified share. + * + * @param {ShareSetQuotaOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + setQuota(): Promise; + setQuota(options: Models.ShareSetQuotaOptionalParams): Promise; + setQuota(callback: msRest.ServiceCallback): void; + setQuota(options: Models.ShareSetQuotaOptionalParams, callback: msRest.ServiceCallback): void; + setQuota(options?: Models.ShareSetQuotaOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + setQuotaOperationSpec, + callback) as Promise; + } + + /** + * Sets one or more user-defined name-value pairs for the specified share. + * + * @param {ShareSetMetadataOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + setMetadata(): Promise; + setMetadata(options: Models.ShareSetMetadataOptionalParams): Promise; + setMetadata(callback: msRest.ServiceCallback): void; + setMetadata(options: Models.ShareSetMetadataOptionalParams, callback: msRest.ServiceCallback): void; + setMetadata(options?: Models.ShareSetMetadataOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + setMetadataOperationSpec, + callback) as Promise; + } + + /** + * Returns information about stored access policies specified on the share. + * + * @param {ShareGetAccessPolicyOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + getAccessPolicy(): Promise; + getAccessPolicy(options: Models.ShareGetAccessPolicyOptionalParams): Promise; + getAccessPolicy(callback: msRest.ServiceCallback): void; + getAccessPolicy(options: Models.ShareGetAccessPolicyOptionalParams, callback: msRest.ServiceCallback): void; + getAccessPolicy(options?: Models.ShareGetAccessPolicyOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + getAccessPolicyOperationSpec, + callback) as Promise; + } + + /** + * Sets a stored access policy for use with shared access signatures. + * + * @param {ShareSetAccessPolicyOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + setAccessPolicy(): Promise; + setAccessPolicy(options: Models.ShareSetAccessPolicyOptionalParams): Promise; + setAccessPolicy(callback: msRest.ServiceCallback): void; + setAccessPolicy(options: Models.ShareSetAccessPolicyOptionalParams, callback: msRest.ServiceCallback): void; + setAccessPolicy(options?: Models.ShareSetAccessPolicyOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + setAccessPolicyOperationSpec, + callback) as Promise; + } + + /** + * Retrieves statistics related to the share. + * + * @param {ShareGetStatisticsOptionalParams} [options] Optional Parameters. + * + * @returns {Promise} A promise is returned + * + * @resolve {HttpOperationResponse} The deserialized result object. + * + * @reject {Error|ServiceError} The error object. + */ + getStatistics(): Promise; + getStatistics(options: Models.ShareGetStatisticsOptionalParams): Promise; + getStatistics(callback: msRest.ServiceCallback): void; + getStatistics(options: Models.ShareGetStatisticsOptionalParams, callback: msRest.ServiceCallback): void; + getStatistics(options?: Models.ShareGetStatisticsOptionalParams, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + options + }, + getStatisticsOperationSpec, + callback) as Promise; + } + +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers, true); +const createOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype1 + ], + headerParameters: [ + Parameters.metadata, + Parameters.quota, + Parameters.version + ], + responses: { + 201: { + headersMapper: Mappers.ShareCreateHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const getPropertiesOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{shareName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.sharesnapshot, + Parameters.timeout, + Parameters.restype1 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.ShareGetPropertiesHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const deleteMethodOperationSpec: msRest.OperationSpec = { + httpMethod: "DELETE", + path: "{shareName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.sharesnapshot, + Parameters.timeout, + Parameters.restype1 + ], + headerParameters: [ + Parameters.version, + Parameters.deleteSnapshots + ], + responses: { + 202: { + headersMapper: Mappers.ShareDeleteHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const createSnapshotOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype1, + Parameters.comp2 + ], + headerParameters: [ + Parameters.metadata, + Parameters.version + ], + responses: { + 201: { + headersMapper: Mappers.ShareCreateSnapshotHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const setQuotaOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype1, + Parameters.comp0 + ], + headerParameters: [ + Parameters.version, + Parameters.quota + ], + responses: { + 200: { + headersMapper: Mappers.ShareSetQuotaHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const setMetadataOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype1, + Parameters.comp3 + ], + headerParameters: [ + Parameters.metadata, + Parameters.version + ], + responses: { + 200: { + headersMapper: Mappers.ShareSetMetadataHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const getAccessPolicyOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{shareName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype1, + Parameters.comp4 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + bodyMapper: { + xmlElementName: "SignedIdentifiers", + serializedName: "parsedResponse", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "SignedIdentifier" + } + } + } + }, + headersMapper: Mappers.ShareGetAccessPolicyHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const setAccessPolicyOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "{shareName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype1, + Parameters.comp4 + ], + headerParameters: [ + Parameters.version + ], + requestBody: { + parameterPath: [ + "options", + "shareAcl" + ], + mapper: { + xmlName: "SignedIdentifiers", + xmlElementName: "SignedIdentifiers", + serializedName: "shareAcl", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "SignedIdentifier" + } + } + } + } + }, + contentType: "application/xml; charset=utf-8", + responses: { + 200: { + headersMapper: Mappers.ShareSetAccessPolicyHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; + +const getStatisticsOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "{shareName}", + urlParameters: [ + Parameters.url + ], + queryParameters: [ + Parameters.timeout, + Parameters.restype1, + Parameters.comp5 + ], + headerParameters: [ + Parameters.version + ], + responses: { + 200: { + bodyMapper: Mappers.ShareStats, + headersMapper: Mappers.ShareGetStatisticsHeaders + }, + default: { + bodyMapper: Mappers.StorageError + } + }, + isXML: true, + serializer +}; diff --git a/file/lib/generated/storageClient.ts b/file/lib/generated/storageClient.ts new file mode 100644 index 0000000..1a50d4c --- /dev/null +++ b/file/lib/generated/storageClient.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "ms-rest-js"; +import * as Models from "./models"; +import * as Mappers from "./models/mappers"; +import * as operations from "./operations"; +import { StorageClientContext } from "./storageClientContext"; + +class StorageClient extends StorageClientContext { + // Operation groups + service: operations.Service; + share: operations.Share; + directory: operations.Directory; + file: operations.File; + + /** + * @class + * Initializes a new instance of the StorageClient class. + * @constructor + * + * @param {object} [options] - The parameter options + * + * @param {Array} [options.filters] - Filters to be added to the request pipeline + * + * @param {object} [options.requestOptions] - The request options. Detailed info can be found at + * {@link https://github.github.io/fetch/#Request Options doc} + * + * @param {boolean} [options.noRetryPolicy] - If set to true, turn off default retry policy + * + */ + constructor(version: string, url: string, options?: msRest.ServiceClientOptions) { + super(version, url, options); + this.service = new operations.Service(this); + this.share = new operations.Share(this); + this.directory = new operations.Directory(this); + this.file = new operations.File(this); + } +} + +// Operation Specifications + +export { + StorageClient, + StorageClientContext, + Models as StorageModels, + Mappers as StorageMappers +}; +export * from "./operations"; diff --git a/file/lib/generated/storageClientContext.ts b/file/lib/generated/storageClientContext.ts new file mode 100644 index 0000000..7060bb2 --- /dev/null +++ b/file/lib/generated/storageClientContext.ts @@ -0,0 +1,60 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "ms-rest-js"; + +const packageName = ""; +const packageVersion = ""; + +export class StorageClientContext extends msRest.ServiceClient { + version: string; + url: string; + + /** + * @class + * Initializes a new instance of the StorageClientContext class. + * @constructor + * + * @param {string} version - Specifies the version of the operation to use for this request. + * + * @param {string} url - The URL of the service account, share, directory or file that is the target of the desired operation. + * + * @param {object} [options] - The parameter options + * + * @param {Array} [options.filters] - Filters to be added to the request pipeline + * + * @param {object} [options.requestOptions] - The request options. Detailed info can be found at + * {@link https://github.github.io/fetch/#Request Options doc} + * + * @param {boolean} [options.noRetryPolicy] - If set to true, turn off default retry policy + * + */ + constructor(version: string, url: string, options?: msRest.ServiceClientOptions) { + if (version === null || version === undefined) { + throw new Error('\'version\' cannot be null.'); + } + if (url === null || url === undefined) { + throw new Error('\'url\' cannot be null.'); + } + + if (!options) { + options = {}; + } + + super(undefined, options); + + this.baseUri = "{url}"; + this.requestContentType = "application/json; charset=utf-8"; + this.version = version; + this.url = url; + + this.addUserAgentInfo(`${packageName}/${packageVersion}`); + } +} diff --git a/file/lib/highlevel.browser.ts b/file/lib/highlevel.browser.ts new file mode 100644 index 0000000..878a40b --- /dev/null +++ b/file/lib/highlevel.browser.ts @@ -0,0 +1,156 @@ +import { generateUuid } from "ms-rest-js"; + +import { Aborter } from "./Aborter"; +import { BlockBlobURL } from "./BlockBlobURL"; +import { + BlobUploadCommonResponse, + IUploadToBlockBlobOptions +} from "./highlevel.common"; +import { Batch } from "./utils/Batch"; +import { + BLOB_DEFAULT_DOWNLOAD_BLOCK_BYTES, + BLOCK_BLOB_MAX_BLOCKS, + BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES, + BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES +} from "./utils/constants"; +import { generateBlockID } from "./utils/utils.common"; + +/** + * ONLY AVAILABLE IN BROWSERS. + * + * Uploads a browser Blob/File/ArrayBuffer/ArrayBufferView object to block blob. + * + * When buffer length <= 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. + * + * @export + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {Blob | ArrayBuffer | ArrayBufferView} browserData Blob, File, ArrayBuffer or ArrayBufferView + * @param {BlockBlobURL} blockBlobURL + * @param {IUploadToBlockBlobOptions} [options] + * @returns {Promise} + */ +export async function uploadBrowserDataToBlockBlob( + aborter: Aborter, + browserData: Blob | ArrayBuffer | ArrayBufferView, + blockBlobURL: BlockBlobURL, + options?: IUploadToBlockBlobOptions +): Promise { + const browserBlob = new Blob([browserData]); + return UploadSeekableBlobToBlockBlob( + aborter, + (offset: number, size: number): Blob => { + return browserBlob.slice(offset, offset + size); + }, + browserBlob.size, + blockBlobURL, + options + ); +} + +/** + * ONLY AVAILABLE IN BROWSERS. + * + * Uploads a browser Blob object to block blob. Requires a blobFactory as the data source, + * which need to return a Blob object with the offset and size provided. + * + * When buffer length <= 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 {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {(offset: number, size: number) => Blob} blobFactory + * @param {number} size + * @param {BlockBlobURL} blockBlobURL + * @param {IUploadToBlockBlobOptions} [options] + * @returns {Promise} + */ +async function UploadSeekableBlobToBlockBlob( + aborter: Aborter, + blobFactory: (offset: number, size: number) => Blob, + size: number, + blockBlobURL: BlockBlobURL, + options: IUploadToBlockBlobOptions = {} +): Promise { + if (!options.blockSize) { + options.blockSize = 0; + } + if ( + options.blockSize < 0 || + options.blockSize > BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES + ) { + throw new RangeError( + `blockSize option must be >= 0 and <= ${BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES}` + ); + } + if (options.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 > BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES) { + options.blockSize = Math.ceil(size / BLOCK_BLOB_MAX_BLOCKS); + if (options.blockSize < BLOB_DEFAULT_DOWNLOAD_BLOCK_BYTES) { + options.blockSize = BLOB_DEFAULT_DOWNLOAD_BLOCK_BYTES; + } + } + } + if (!options.blobHTTPHeaders) { + options.blobHTTPHeaders = {}; + } + if (!options.blobAccessConditions) { + options.blobAccessConditions = {}; + } + + if (size <= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES) { + return blockBlobURL.upload(aborter, blobFactory(0, size), size, options); + } + + const numBlocks: number = Math.floor((size - 1) / options.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: string[] = []; + const blockIDPrefix = generateUuid(); + let transferProgress: number = 0; + + const batch = new Batch(options.parallelism); + for (let i = 0; i < numBlocks; i++) { + batch.addOperation( + async (): Promise => { + const blockID = generateBlockID(blockIDPrefix, i); + const start = options.blockSize! * i; + const end = i === numBlocks - 1 ? size : start + options.blockSize!; + const contentLength = end - start; + blockList.push(blockID); + await blockBlobURL.stageBlock( + aborter, + blockID, + blobFactory(start, contentLength), + contentLength, + { + leaseAccessConditions: options.blobAccessConditions! + .leaseAccessConditions + } + ); + // 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.progress) { + options.progress!({ + loadedBytes: transferProgress + }); + } + } + ); + } + await batch.do(); + + return blockBlobURL.commitBlockList(aborter, blockList, options); +} diff --git a/file/lib/highlevel.common.ts b/file/lib/highlevel.common.ts new file mode 100644 index 0000000..5e9846e --- /dev/null +++ b/file/lib/highlevel.common.ts @@ -0,0 +1,115 @@ +import { HttpResponse, TransferProgressEvent } from "ms-rest-js"; + +import * as Models from "./generated/models"; +import { IBlobAccessConditions } from "./models"; + +/** + * Option interface for uploadFileToBlockBlob and uploadSeekableStreamToBlockBlob. + * + * @export + * @interface IUploadToBlockBlobOptions + */ +export interface IUploadToBlockBlobOptions { + /** + * Destination block blob size. + * + * @type {number} + * @memberof IUploadToBlockBlobOptions + */ + blockSize?: number; + + /** + * Progress updater. + * + * @memberof IUploadToBlockBlobOptions + */ + progress?: (progress: TransferProgressEvent) => void; + + /** + * Blob HTTP Headers. + * + * @type {IBlobHTTPHeaders} + * @memberof IUploadToBlockBlobOptions + */ + blobHTTPHeaders?: Models.BlobHTTPHeaders; + + /** + * Metadata of block blob. + * + * @type {{ [propertyName: string]: string }} + * @memberof IUploadToBlockBlobOptions + */ + metadata?: { [propertyName: string]: string }; + + /** + * Access conditions headers. + * + * @type {IBlobAccessConditions} + * @memberof IUploadToBlockBlobOptions + */ + blobAccessConditions?: IBlobAccessConditions; + + /** + * Concurrency of parallel uploading. Must be >= 0. + * + * @type {number} + * @memberof IUploadToBlockBlobOptions + */ + parallelism?: number; +} + +/** + * Type for uploadFileToBlockBlob, uploadStreamToBlockBlob and uploadBrowserDateToBlockBlob. + * + * @export + */ +export type BlobUploadCommonResponse = Models.BlockBlobUploadHeaders & { + /** + * The underlying HTTP response. + * + * @type {HttpResponse} + * @memberof IBlobUploadCommonResponse + */ + _response: HttpResponse; +}; + +/** + * Option interface for DownloadBlockBlobToBuffer. + * + * @export + * @interface IDownloadFromBlobOptions + */ +export interface IDownloadFromBlobOptions { + /** + * blockSize is the data every request trying to download. + * Must be >= 0, if set to 0 or undefined, blockSize will automatically calculated according + * to the blob size. + * + * @type {number} + * @memberof IDownloadFromBlobOptions + */ + blockSize?: number; + + /** + * Progress updater. + * + * @memberof IDownloadFromBlobOptions + */ + progress?: (progress: TransferProgressEvent) => void; + + /** + * Access conditions headers. + * + * @type {IBlobAccessConditions} + * @memberof IDownloadFromBlobOptions + */ + blobAccessConditions?: IBlobAccessConditions; + + /** + * Concurrency of parallel download. + * + * @type {number} + * @memberof IDownloadFromBlobOptions + */ + parallelism?: number; +} diff --git a/file/lib/highlevel.node.ts b/file/lib/highlevel.node.ts new file mode 100644 index 0000000..ac5ef61 --- /dev/null +++ b/file/lib/highlevel.node.ts @@ -0,0 +1,367 @@ +import * as fs from "fs"; +import { generateUuid, TransferProgressEvent } from "ms-rest-js"; +import { Readable } from "stream"; + +import { Aborter } from "./Aborter"; +import { BlobURL } from "./BlobURL"; +import { BlockBlobURL } from "./BlockBlobURL"; +import { BlobHTTPHeaders } from "./generated/models"; +import { + BlobUploadCommonResponse, + IDownloadFromBlobOptions, + IUploadToBlockBlobOptions +} from "./highlevel.common"; +import { IBlobAccessConditions } from "./models"; +import { Batch } from "./utils/Batch"; +import { BufferScheduler } from "./utils/BufferScheduler"; +import { + BLOB_DEFAULT_DOWNLOAD_BLOCK_BYTES, + BLOCK_BLOB_MAX_BLOCKS, + BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES, + BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES +} from "./utils/constants"; +import { generateBlockID } from "./utils/utils.common"; +import { streamToBuffer } from "./utils/utils.node"; + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * Uploads a local file in blocks to a block blob. + * + * When file size <= 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. + * + * @export + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {string} filePath Full path of local file + * @param {BlockBlobURL} blockBlobURL BlockBlobURL + * @param {IUploadToBlockBlobOptions} [options] IUploadToBlockBlobOptions + * @returns {(Promise)} ICommonResponse + */ +export async function uploadFileToBlockBlob( + aborter: Aborter, + filePath: string, + blockBlobURL: BlockBlobURL, + options?: IUploadToBlockBlobOptions +): Promise { + const size = fs.statSync(filePath).size; + return uploadResetableStreamToBlockBlob( + aborter, + (offset, count) => + fs.createReadStream(filePath, { + autoClose: true, + end: count ? offset + count - 1 : Infinity, + start: offset + }), + size, + blockBlobURL, + options + ); +} + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * Accepts a Node.js Readable stream factory, and uploads in blocks to a block blob. + * The Readable stream factory must returns a Node.js Readable stream starting from the offset defined. The offset + * is the offset in the block blob to be uploaded. + * + * When buffer length <= 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. + * + * @export + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {(offset: number) => NodeJS.ReadableStream} streamFactory Returns a Node.js Readable stream starting + * from the offset defined + * @param {number} size Size of the block blob + * @param {BlockBlobURL} blockBlobURL BlockBlobURL + * @param {IUploadToBlockBlobOptions} [options] IUploadToBlockBlobOptions + * @returns {(Promise)} ICommonResponse + */ +async function uploadResetableStreamToBlockBlob( + aborter: Aborter, + streamFactory: (offset: number, count?: number) => NodeJS.ReadableStream, + size: number, + blockBlobURL: BlockBlobURL, + options: IUploadToBlockBlobOptions = {} +): Promise { + if (!options.blockSize) { + options.blockSize = 0; + } + if ( + options.blockSize < 0 || + options.blockSize > BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES + ) { + throw new RangeError( + `blockSize option must be >= 0 and <= ${BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES}` + ); + } + if (options.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 > BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES) { + options.blockSize = Math.ceil(size / BLOCK_BLOB_MAX_BLOCKS); + if (options.blockSize < BLOB_DEFAULT_DOWNLOAD_BLOCK_BYTES) { + options.blockSize = BLOB_DEFAULT_DOWNLOAD_BLOCK_BYTES; + } + } + } + if (!options.blobHTTPHeaders) { + options.blobHTTPHeaders = {}; + } + if (!options.blobAccessConditions) { + options.blobAccessConditions = {}; + } + + if (size <= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES) { + return blockBlobURL.upload(aborter, () => streamFactory(0), size, options); + } + + const numBlocks: number = Math.floor((size - 1) / options.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: string[] = []; + const blockIDPrefix = generateUuid(); + let transferProgress: number = 0; + + const batch = new Batch(options.parallelism); + for (let i = 0; i < numBlocks; i++) { + batch.addOperation( + async (): Promise => { + const blockID = generateBlockID(blockIDPrefix, i); + const start = options.blockSize! * i; + const end = i === numBlocks - 1 ? size : start + options.blockSize!; + const contentLength = end - start; + blockList.push(blockID); + await blockBlobURL.stageBlock( + aborter, + blockID, + () => streamFactory(start, contentLength), + contentLength, + { + leaseAccessConditions: options.blobAccessConditions! + .leaseAccessConditions + } + ); + // Update progress after block is successfully uploaded to server, in case of block trying + transferProgress += contentLength; + if (options.progress) { + options.progress({ loadedBytes: transferProgress }); + } + } + ); + } + await batch.do(); + + return blockBlobURL.commitBlockList(aborter, blockList, options); +} + +/** + * ONLY AVAILABLE IN NODE.JS RUNTIME. + * + * Downloads an Azure Blob in parallel to a buffer. + * Offset and count are optional, pass 0 for both to download the entire blob. + * + * @export + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {Buffer} buffer Buffer to be fill, must have length larger than count + * @param {BlobURL} blobURL A BlobURL object + * @param {number} offset From which position of the block blob to download + * @param {number} [count] How much data to be downloaded. Will download to the end when passing undefined + * @param {IDownloadFromBlobOptions} [options] IDownloadFromBlobOptions + * @returns {Promise} + */ +export async function downloadBlobToBuffer( + aborter: Aborter, + buffer: Buffer, + blobURL: BlobURL, + offset: number, + count?: number, + options: IDownloadFromBlobOptions = {} +): Promise { + if (!options.blockSize) { + options.blockSize = 0; + } + if (options.blockSize < 0) { + throw new RangeError("blockSize option must be >= 0"); + } + if (options.blockSize === 0) { + options.blockSize = BLOB_DEFAULT_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 > 0"); + } + + if (!options.blobAccessConditions) { + options.blobAccessConditions = {}; + } + + // Customer doesn't specify length, get it + if (!count) { + const response = await blobURL.getProperties(aborter, options); + count = response.contentLength! - offset; + if (count < 0) { + throw new RangeError( + `offset ${offset} shouldn't be larger than blob size ${response.contentLength!}` + ); + } + } + + 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: number = 0; + const batch = new Batch(options.parallelism); + for (let off = offset; off < offset + count; off = off + options.blockSize) { + batch.addOperation(async () => { + const chunkEnd = + off + options.blockSize! < count! ? off + options.blockSize! : count!; + const response = await blobURL.download( + aborter, + off, + chunkEnd - off + 1, + { + blobAccessConditions: options.blobAccessConditions + } + ); + 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.progress) { + options.progress({ loadedBytes: transferProgress }); + } + }); + } + await batch.do(); +} + +/** + * Option interface for uploadStreamToBlockBlob. + * + * @export + * @interface IUploadStreamToBlockBlobOptions + */ +export interface IUploadStreamToBlockBlobOptions { + /** + * Blob HTTP Headers. + * + * @type {BlobHTTPHeaders} + * @memberof IUploadStreamToBlockBlobOptions + */ + blobHTTPHeaders?: BlobHTTPHeaders; + + /** + * Metadata of block blob. + * + * @type {{ [propertyName: string]: string }} + * @memberof IUploadStreamToBlockBlobOptions + */ + metadata?: { [propertyName: string]: string }; + + /** + * Access conditions headers. + * + * @type {IBlobAccessConditions} + * @memberof IUploadStreamToBlockBlobOptions + */ + accessConditions?: IBlobAccessConditions; + + /** + * Progress updater. + * + * @memberof IUploadStreamToBlockBlobOptions + */ + progress?: (progress: TransferProgressEvent) => void; +} + +/** + * 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. + * + * @export + * @param {Aborter} aborter Create a new Aborter instance with Aborter.none or Aborter.timeout(), + * goto documents of Aborter for more examples about request cancellation + * @param {Readable} stream Node.js Readable stream + * @param {BlockBlobURL} blockBlobURL A BlockBlobURL instance + * @param {number} bufferSize Size of every buffer allocated, also the block size in the uploaded block blob + * @param {number} maxBuffers Max buffers will allocate during uploading, positive correlation + * with max uploading concurrency + * @param {IUploadStreamToBlockBlobOptions} [options] + * @returns {Promise} + */ +export async function uploadStreamToBlockBlob( + aborter: Aborter, + stream: Readable, + blockBlobURL: BlockBlobURL, + bufferSize: number, + maxBuffers: number, + options: IUploadStreamToBlockBlobOptions = {} +): Promise { + if (!options.blobHTTPHeaders) { + options.blobHTTPHeaders = {}; + } + if (!options.accessConditions) { + options.accessConditions = {}; + } + + let blockNum = 0; + const blockIDPrefix = generateUuid(); + let transferProgress: number = 0; + const blockList: string[] = []; + + const scheduler = new BufferScheduler( + stream, + bufferSize, + maxBuffers, + async (buffer: Buffer) => { + const blockID = generateBlockID(blockIDPrefix, blockNum); + blockList.push(blockID); + blockNum++; + + await blockBlobURL.stageBlock(aborter, blockID, buffer, buffer.length, { + leaseAccessConditions: options.accessConditions!.leaseAccessConditions + }); + + // Update progress after block is successfully uploaded to server, in case of block trying + transferProgress += buffer.length; + if (options.progress) { + options.progress({ loadedBytes: transferProgress }); + } + }, + // Parallelism should set a smaller value than maxBuffers, 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((maxBuffers / 4) * 3) + ); + await scheduler.do(); + + return blockBlobURL.commitBlockList(aborter, blockList, options); +} diff --git a/file/lib/index.browser.ts b/file/lib/index.browser.ts new file mode 100644 index 0000000..659e95f --- /dev/null +++ b/file/lib/index.browser.ts @@ -0,0 +1,29 @@ +import { RestError } from "ms-rest-js"; + +import * as Models from "../lib/generated/models"; + +export * from "./Aborter"; +export * from "./AppendBlobURL"; +export * from "./BlobURL"; +export * from "./BlockBlobURL"; +export * from "./ContainerURL"; +export * from "./credentials/AnonymousCredential"; +export * from "./credentials/Credential"; +export * from "./credentials/TokenCredential"; +export * from "./highlevel.browser"; +export * from "./highlevel.common"; +export { IIPRange } from "./IIPRange"; +export { IRange } from "./IRange"; +export * from "./PageBlobURL"; +export * from "./Pipeline"; +export * from "./policies/AnonymousCredentialPolicy"; +export * from "./policies/CredentialPolicy"; +export * from "./RetryPolicyFactory"; +export * from "./LoggingPolicyFactory"; +export * from "./TelemetryPolicyFactory"; +export * from "./policies/TokenCredentialPolicy"; +export * from "./UniqueRequestIDPolicyFactory"; +export * from "./SASQueryParameters"; +export * from "./ServiceURL"; +export * from "./StorageURL"; +export { Models, RestError }; diff --git a/file/lib/index.ts b/file/lib/index.ts new file mode 100644 index 0000000..42e736e --- /dev/null +++ b/file/lib/index.ts @@ -0,0 +1,38 @@ +import { RestError } from "ms-rest-js"; + +import * as Models from "../lib/generated/models"; + +export * from "./Aborter"; +export * from "./AccountSASPermissions"; +export * from "./AccountSASResourceTypes"; +export * from "./AccountSASServices"; +export * from "./IAccountSASSignatureValues"; +export * from "./AppendBlobURL"; +export * from "./BlobSASPermissions"; +export * from "./IBlobSASSignatureValues"; +export * from "./BlobURL"; +export * from "./BlockBlobURL"; +export * from "./ContainerSASPermissions"; +export * from "./ContainerURL"; +export * from "./credentials/AnonymousCredential"; +export * from "./credentials/Credential"; +export * from "./credentials/SharedKeyCredential"; +export * from "./credentials/TokenCredential"; +export * from "./highlevel.browser"; +export * from "./highlevel.common"; +export * from "./highlevel.node"; +export { IIPRange } from "./IIPRange"; +export { IRange } from "./IRange"; +export * from "./PageBlobURL"; +export * from "./Pipeline"; +export * from "./policies/AnonymousCredentialPolicy"; +export * from "./policies/CredentialPolicy"; +export * from "./RetryPolicyFactory"; +export * from "./LoggingPolicyFactory"; +export * from "./policies/SharedKeyCredentialPolicy"; +export * from "./TelemetryPolicyFactory"; +export * from "./policies/TokenCredentialPolicy"; +export * from "./UniqueRequestIDPolicyFactory"; +export * from "./ServiceURL"; +export * from "./StorageURL"; +export { Models, RestError }; diff --git a/file/lib/models.ts b/file/lib/models.ts new file mode 100644 index 0000000..7230578 --- /dev/null +++ b/file/lib/models.ts @@ -0,0 +1,23 @@ +import * as Models from "./generated/models"; + +export interface IMetadata { + [propertyName: string]: string; +} + +export interface IContainerAccessConditions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; + leaseAccessConditions?: Models.LeaseAccessConditions; +} + +export interface IBlobAccessConditions { + modifiedAccessConditions?: Models.ModifiedAccessConditions; + leaseAccessConditions?: Models.LeaseAccessConditions; +} + +export interface IPageBlobAccessConditions extends IBlobAccessConditions { + sequenceNumberAccessConditions?: Models.SequenceNumberAccessConditions; +} + +export interface IAppendBlobAccessConditions extends IBlobAccessConditions { + appendPositionAccessConditions?: Models.AppendPositionAccessConditions; +} diff --git a/file/lib/policies/AnonymousCredentialPolicy.ts b/file/lib/policies/AnonymousCredentialPolicy.ts new file mode 100644 index 0000000..e7d5924 --- /dev/null +++ b/file/lib/policies/AnonymousCredentialPolicy.ts @@ -0,0 +1,23 @@ +import { RequestPolicy, RequestPolicyOptions } from "ms-rest-js"; + +import { CredentialPolicy } from "./CredentialPolicy"; + +/** + * AnonymousCredentialPolicy is used with HTTP(S) requests that read public resources + * or for use with Shared Access Signatures (SAS). + * + * @export + * @class AnonymousCredentialPolicy + * @extends {CredentialPolicy} + */ +export class AnonymousCredentialPolicy extends CredentialPolicy { + /** + * Creates an instance of AnonymousCredentialPolicy. + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @memberof AnonymousCredentialPolicy + */ + constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions) { + super(nextPolicy, options); + } +} diff --git a/file/lib/policies/BrowserPolicy.ts b/file/lib/policies/BrowserPolicy.ts new file mode 100644 index 0000000..5f417e7 --- /dev/null +++ b/file/lib/policies/BrowserPolicy.ts @@ -0,0 +1,70 @@ +import { + BaseRequestPolicy, + HttpOperationResponse, + isNode, + RequestPolicy, + RequestPolicyOptions, + WebResource +} from "ms-rest-js"; + +import { HeaderConstants, URLConstants } from "../utils/constants"; +import { setURLParameter } from "../utils/utils.common"; + +/** + * BrowserPolicy 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'. + * BrowserPolicy 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 + * + * @class BrowserPolicy + * @extends {BaseRequestPolicy} + */ +export class BrowserPolicy extends BaseRequestPolicy { + /** + * Creates an instance of BrowserPolicy. + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @memberof BrowserPolicy + */ + constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions) { + super(nextPolicy, options); + } + + /** + * Sends out request. + * + * @param {WebResource} request + * @returns {Promise} + * @memberof BrowserPolicy + */ + public async sendRequest( + request: WebResource + ): Promise { + if (isNode) { + return this._nextPolicy.sendRequest(request); + } + + if ( + request.method.toUpperCase() === "GET" || + request.method.toUpperCase() === "HEAD" + ) { + request.url = setURLParameter( + request.url, + URLConstants.Parameters.FORCE_BROWSER_NO_CACHE, + new Date().getTime().toString() + ); + } + + request.headers.remove(HeaderConstants.COOKIE); + + // According to XHR standards, content-length should be fully controlled by browsers + request.headers.remove(HeaderConstants.CONTENT_LENGTH); + + return this._nextPolicy.sendRequest(request); + } +} diff --git a/file/lib/policies/CredentialPolicy.ts b/file/lib/policies/CredentialPolicy.ts new file mode 100644 index 0000000..1a5dcc7 --- /dev/null +++ b/file/lib/policies/CredentialPolicy.ts @@ -0,0 +1,43 @@ +import { + BaseRequestPolicy, + HttpOperationResponse, + WebResource +} from "ms-rest-js"; + +/** + * Credential policy used to sign HTTP(S) requests before sending. This is an + * abstract class. + * + * @export + * @abstract + * @class CredentialPolicy + * @extends {BaseRequestPolicy} + */ +export abstract class CredentialPolicy extends BaseRequestPolicy { + /** + * Sends out request. + * + * @param {WebResource} request + * @returns {Promise} + * @memberof CredentialPolicy + */ + public sendRequest(request: WebResource): Promise { + return this._nextPolicy.sendRequest(this.signRequest(request)); + } + + /** + * Child classes must implement this method with request signing. This method + * will be executed in sendRequest(). + * + * @protected + * @abstract + * @param {WebResource} request + * @returns {WebResource} + * @memberof CredentialPolicy + */ + protected signRequest(request: WebResource): WebResource { + // Child classes must override this method with request signing. This method + // will be executed in sendRequest(). + return request; + } +} diff --git a/file/lib/policies/LoggingPolicy.ts b/file/lib/policies/LoggingPolicy.ts new file mode 100644 index 0000000..0e4f35d --- /dev/null +++ b/file/lib/policies/LoggingPolicy.ts @@ -0,0 +1,141 @@ +import { + BaseRequestPolicy, + HttpOperationResponse, + HttpPipelineLogLevel, + RequestPolicy, + RequestPolicyOptions, + WebResource +} from "ms-rest-js"; + +import { IRequestLogOptions } from "../LoggingPolicyFactory"; +import { HTTPURLConnection, URLConstants } from "../utils/constants"; +import { getURLParameter, setURLParameter } from "../utils/utils.common"; + +// Default values of IRetryOptions +const DEFAULT_REQUEST_LOG_OPTIONS: IRequestLogOptions = { + logWarningIfTryOverThreshold: 3000 +}; + +/** + * LoggingPolicy is a policy used to log requests. + * + * @class LoggingPolicy + * @extends {BaseRequestPolicy} + */ +export class LoggingPolicy extends BaseRequestPolicy { + private tryCount: number = 0; + private operationStartTime: Date = new Date(); + private requestStartTime: Date = new Date(); + + private readonly loggingOptions: IRequestLogOptions; + + /** + * Creates an instance of LoggingPolicy. + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @param {IRequestLogOptions} [loggingOptions=DEFAULT_REQUEST_LOG_OPTIONS] + * @memberof LoggingPolicy + */ + constructor( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions, + loggingOptions: IRequestLogOptions = DEFAULT_REQUEST_LOG_OPTIONS + ) { + super(nextPolicy, options); + this.loggingOptions = loggingOptions; + } + + /** + * Sends out request. + * + * @param {WebResource} request + * @returns {Promise} + * @memberof LoggingPolicy + */ + public async sendRequest( + request: WebResource + ): Promise { + this.tryCount++; + this.requestStartTime = new Date(); + if (this.tryCount === 1) { + this.operationStartTime = this.requestStartTime; + } + + let safeURL: string = request.url; + if (getURLParameter(safeURL, URLConstants.Parameters.SIGNATURE)) { + safeURL = setURLParameter( + safeURL, + URLConstants.Parameters.SIGNATURE, + "*****" + ); + } + this.log( + HttpPipelineLogLevel.INFO, + `'${safeURL}'==> OUTGOING REQUEST (Try number=${this.tryCount}).` + ); + + try { + const response = await this._nextPolicy.sendRequest(request); + + const requestEndTime = new Date(); + const requestCompletionTime = + requestEndTime.getTime() - this.requestStartTime.getTime(); + const operationDuration = + requestEndTime.getTime() - this.operationStartTime.getTime(); + + let currentLevel: HttpPipelineLogLevel = HttpPipelineLogLevel.INFO; + let logMessage: string = ""; + if (this.shouldLog(HttpPipelineLogLevel.INFO)) { + // Assume success and default to informational logging. + logMessage = "Successfully Received Response. "; + } + + // If the response took too long, we'll upgrade to warning. + if ( + requestCompletionTime >= + this.loggingOptions.logWarningIfTryOverThreshold + ) { + // Log a warning if the try duration exceeded the specified threshold. + if (this.shouldLog(HttpPipelineLogLevel.WARNING)) { + currentLevel = HttpPipelineLogLevel.WARNING; + logMessage = `SLOW OPERATION. Duration > ${ + this.loggingOptions.logWarningIfTryOverThreshold + } ms. `; + } + } + + if ( + (response.status >= 400 && + response.status <= 499 && + (response.status !== HTTPURLConnection.HTTP_NOT_FOUND && + response.status !== HTTPURLConnection.HTTP_CONFLICT && + response.status !== HTTPURLConnection.HTTP_PRECON_FAILED && + response.status !== + HTTPURLConnection.HTTP_RANGE_NOT_SATISFIABLE)) || + (response.status >= 500 && response.status <= 509) + ) { + const errorString = `REQUEST ERROR: HTTP request failed with status code: ${ + response.status + }. `; + logMessage = errorString; + + currentLevel = HttpPipelineLogLevel.ERROR; + } + + const messageInfo = `Request try:${this.tryCount}, status:${ + response.status + } request duration:${requestCompletionTime} ms, operation duration:${operationDuration} ms\n`; + this.log(currentLevel, logMessage + messageInfo); + + return response; + } catch (err) { + this.log( + HttpPipelineLogLevel.ERROR, + `Unexpected failure attempting to make request. Error message: ${ + err.message + }` + ); + throw err; + } + } +} diff --git a/file/lib/policies/RetryPolicy.ts b/file/lib/policies/RetryPolicy.ts new file mode 100644 index 0000000..58d2800 --- /dev/null +++ b/file/lib/policies/RetryPolicy.ts @@ -0,0 +1,347 @@ +import { + BaseRequestPolicy, + delay, + HttpOperationResponse, + HttpPipelineLogLevel, + RequestPolicy, + RequestPolicyFactory, + RequestPolicyOptions, + RestError, + WebResource +} from "ms-rest-js"; + +import { IRetryOptions } from "../RetryPolicyFactory"; +import { URLConstants } from "../utils/constants"; +import { setURLHost, setURLParameter } from "../utils/utils.common"; + +/** + * A factory method used to generated a RetryPolicy factory. + * + * @export + * @param {IRetryOptions} retryOptions + * @returns + */ +export function NewRetryPolicyFactory( + retryOptions?: IRetryOptions +): RequestPolicyFactory { + return { + create: ( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions + ): RetryPolicy => { + return new RetryPolicy(nextPolicy, options, retryOptions); + } + }; +} + +/** + * RetryPolicy types. + * + * @export + * @enum {number} + */ +export enum RetryPolicyType { + /** + * Exponential retry. Retry time delay grows exponentially. + */ + EXPONENTIAL, + /** + * Linear retry. Retry time delay grows linearly. + */ + FIXED +} + +// Default values of IRetryOptions +const DEFAULT_RETRY_OPTIONS: IRetryOptions = { + maxRetryDelayInMs: 120 * 1000, + maxTries: 4, + retryDelayInMs: 4 * 1000, + retryPolicyType: RetryPolicyType.EXPONENTIAL, + secondaryHost: "", + tryTimeout: 60 +}; + +/** + * Retry policy with exponential retry and linear retry implemented. + * + * @class RetryPolicy + * @extends {BaseRequestPolicy} + */ +export class RetryPolicy extends BaseRequestPolicy { + /** + * RetryOptions. + * + * @private + * @type {IRetryOptions} + * @memberof RetryPolicy + */ + private readonly retryOptions: IRetryOptions; + + /** + * Creates an instance of RetryPolicy. + * + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @param {IRetryOptions} [retryOptions=DEFAULT_RETRY_OPTIONS] + * @memberof RetryPolicy + */ + constructor( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions, + retryOptions: IRetryOptions = DEFAULT_RETRY_OPTIONS + ) { + super(nextPolicy, options); + + // Initialize retry options + this.retryOptions = { + retryPolicyType: retryOptions.retryPolicyType + ? retryOptions.retryPolicyType + : DEFAULT_RETRY_OPTIONS.retryPolicyType, + + maxTries: + retryOptions.maxTries && retryOptions.maxTries >= 1 + ? Math.floor(retryOptions.maxTries) + : DEFAULT_RETRY_OPTIONS.maxTries, + + tryTimeout: + retryOptions.tryTimeout && retryOptions.tryTimeout >= 0 + ? retryOptions.tryTimeout + : DEFAULT_RETRY_OPTIONS.tryTimeout, + + retryDelayInMs: + retryOptions.retryDelayInMs && retryOptions.retryDelayInMs >= 0 + ? Math.min( + retryOptions.retryDelayInMs, + retryOptions.maxRetryDelayInMs + ? retryOptions.maxRetryDelayInMs + : DEFAULT_RETRY_OPTIONS.maxRetryDelayInMs! + ) + : DEFAULT_RETRY_OPTIONS.retryDelayInMs, + + maxRetryDelayInMs: + retryOptions.maxRetryDelayInMs && retryOptions.maxRetryDelayInMs >= 0 + ? retryOptions.maxRetryDelayInMs + : DEFAULT_RETRY_OPTIONS.maxRetryDelayInMs, + + secondaryHost: retryOptions.secondaryHost + ? retryOptions.secondaryHost + : DEFAULT_RETRY_OPTIONS.secondaryHost + }; + } + + /** + * Sends request. + * + * @param {WebResource} request + * @returns {Promise} + * @memberof RetryPolicy + */ + public async sendRequest( + request: WebResource + ): Promise { + return this.attemptSendRequest(request, false, 1); + } + + /** + * Decide and perform next retry. Won't mutate request parameter. + * + * @protected + * @param {WebResource} request + * @param {HttpOperationResponse} response + * @param {boolean} 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 {number} attempt How many retries has been attempted to performed, starting from 1, which includes + * the attempt will be performed by this method call. + * @returns {Promise} + * @memberof RetryPolicy + */ + protected async attemptSendRequest( + request: WebResource, + secondaryHas404: boolean, + attempt: number + ): Promise { + const newRequest: WebResource = 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]" + newRequest.url = setURLParameter( + newRequest.url, + URLConstants.Parameters.TIMEOUT, + this.retryOptions.tryTimeout!.toString() + ); + + let response: HttpOperationResponse | undefined; + try { + this.logf( + HttpPipelineLogLevel.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) { + this.logf( + HttpPipelineLogLevel.ERROR, + `RetryPolicy: Caught error, message: ${err.message}, code: ${err.code}` + ); + if (!this.shouldRetry(isPrimaryRetry, attempt, response, err)) { + throw err; + } + } + + await this.delay(isPrimaryRetry, attempt); + return await this.attemptSendRequest(request, secondaryHas404, ++attempt); + } + + /** + * Decide whether to retry according to last HTTP response and retry counters. + * + * @protected + * @param {boolean} isPrimaryRetry + * @param {number} attempt + * @param {HttpOperationResponse} [response] + * @param {RestError} [err] + * @returns {boolean} + * @memberof RetryPolicy + */ + protected shouldRetry( + isPrimaryRetry: boolean, + attempt: number, + response?: HttpOperationResponse, + err?: RestError + ): boolean { + if (attempt >= this.retryOptions.maxTries!) { + this.logf( + HttpPipelineLogLevel.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", + "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.toUpperCase().includes(retriableError)) + ) { + this.logf( + HttpPipelineLogLevel.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) { + this.logf( + HttpPipelineLogLevel.INFO, + `RetryPolicy: Secondary access with 404, will retry.` + ); + return true; + } + + // Server internal error or server timeout + if (statusCode === 503 || statusCode === 500) { + this.logf( + HttpPipelineLogLevel.INFO, + `RetryPolicy: Will retry for status code ${statusCode}.` + ); + return true; + } + } + + return false; + } + + /** + * This is to log for debugging purposes only. + * Comment/uncomment as necessary for releasing/debugging. + * + * @private + * @param {HttpPipelineLogLevel} level + * @param {string} message + * @memberof RetryPolicy + */ + // tslint:disable-next-line:variable-name + private logf(_level: HttpPipelineLogLevel, _message: string) { + // this.log(_level, _message); + } + + /** + * Delay a calculated time between retries. + * + * @private + * @param {boolean} isPrimaryRetry + * @param {number} attempt + * @returns + * @memberof RetryPolicy + */ + private async delay(isPrimaryRetry: boolean, attempt: number) { + let delayTimeInMs: number = 0; + + if (isPrimaryRetry) { + switch (this.retryOptions.retryPolicyType) { + case RetryPolicyType.EXPONENTIAL: + delayTimeInMs = Math.min( + (Math.pow(2, attempt - 1) - 1) * this.retryOptions.retryDelayInMs!, + this.retryOptions.maxRetryDelayInMs! + ); + break; + case RetryPolicyType.FIXED: + delayTimeInMs = this.retryOptions.retryDelayInMs!; + break; + } + } else { + delayTimeInMs = Math.random() * 1000; + } + + this.logf( + HttpPipelineLogLevel.INFO, + `RetryPolicy: Delay for ${delayTimeInMs}ms` + ); + return delay(delayTimeInMs); + } +} diff --git a/file/lib/policies/SharedKeyCredentialPolicy.ts b/file/lib/policies/SharedKeyCredentialPolicy.ts new file mode 100644 index 0000000..c8ef48f --- /dev/null +++ b/file/lib/policies/SharedKeyCredentialPolicy.ts @@ -0,0 +1,206 @@ +import { RequestPolicy, RequestPolicyOptions, WebResource } from "ms-rest-js"; +import { SharedKeyCredential } from "../credentials/SharedKeyCredential"; +import { HeaderConstants } from "../utils/constants"; +import { getURLPath, getURLQueries } from "../utils/utils.common"; +import { CredentialPolicy } from "./CredentialPolicy"; + +/** + * SharedKeyCredentialPolicy is a policy used to sign HTTP request with a shared key. + * + * @export + * @class SharedKeyCredentialPolicy + * @extends {CredentialPolicy} + */ +export class SharedKeyCredentialPolicy extends CredentialPolicy { + /** + * Reference to SharedKeyCredential which generates SharedKeyCredentialPolicy + * + * @type {SharedKeyCredential} + * @memberof SharedKeyCredentialPolicy + */ + private readonly factory: SharedKeyCredential; + + /** + * Creates an instance of SharedKeyCredentialPolicy. + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @param {SharedKeyCredential} factory + * @memberof SharedKeyCredentialPolicy + */ + constructor( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions, + factory: SharedKeyCredential + ) { + super(nextPolicy, options); + this.factory = factory; + } + + /** + * Signs request. + * + * @protected + * @param {WebResource} request + * @returns {WebResource} + * @memberof SharedKeyCredentialPolicy + */ + protected signRequest(request: WebResource): WebResource { + request.headers.set(HeaderConstants.X_MS_DATE, new Date().toUTCString()); + + if ( + request.body && + typeof request.body === "string" && + request.body.length > 0 + ) { + request.headers.set(HeaderConstants.CONTENT_LENGTH, request.body.length); + } + + const stringToSign: string = + [ + 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: string = 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://docs.microsoft.com/en-us/rest/api/storageservices/authenticate-with-shared-key + * + * @private + * @param {WebResource} request + * @param {string} headerName + * @returns {string} + * @memberof SharedKeyCredentialPolicy + */ + private getHeaderValueToSign( + request: WebResource, + headerName: string + ): string { + 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://docs.microsoft.com/en-us/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. + * + * @private + * @param {WebResource} request + * @returns {string} + * @memberof SharedKeyCredentialPolicy + */ + private getCanonicalizedHeadersString(request: WebResource): string { + let headersArray = request.headers.headersArray().filter(value => { + return value.name + .toLowerCase() + .startsWith(HeaderConstants.PREFIX_FOR_STORAGE); + }); + + headersArray.sort( + (a, b): number => { + return a.name.toLowerCase().localeCompare(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: string = ""; + headersArray.forEach(header => { + canonicalizedHeadersStringToSign += `${header.name + .toLowerCase() + .trimRight()}:${header.value.trimLeft()}\n`; + }); + + return canonicalizedHeadersStringToSign; + } + + /** + * Retrieves the webResource canonicalized resource string. + * + * @private + * @param {WebResource} request + * @returns {string} + * @memberof SharedKeyCredentialPolicy + */ + private getCanonicalizedResourceString(request: WebResource): string { + const path = encodeURI(getURLPath(request.url) || "/"); + + let canonicalizedResourceString: string = ""; + canonicalizedResourceString += `/${this.factory.accountName}${path}`; + + const queries = getURLQueries(request.url); + const lowercaseQueries: { [key: string]: string } = {}; + if (queries) { + const queryKeys: string[] = []; + for (const key in queries) { + if (queries.hasOwnProperty(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; + } +} diff --git a/file/lib/policies/TelemetryPolicy.ts b/file/lib/policies/TelemetryPolicy.ts new file mode 100644 index 0000000..a4b1c77 --- /dev/null +++ b/file/lib/policies/TelemetryPolicy.ts @@ -0,0 +1,65 @@ +import { + BaseRequestPolicy, + HttpHeaders, + HttpOperationResponse, + isNode, + RequestPolicy, + RequestPolicyOptions, + WebResource +} from "ms-rest-js"; + +import { HeaderConstants } from "../utils/constants"; + +/** + * TelemetryPolicy is a policy used to tag user-agent header for every requests. + * + * @class TelemetryPolicy + * @extends {BaseRequestPolicy} + */ +export class TelemetryPolicy extends BaseRequestPolicy { + /** + * Telemetry string. + * + * @type {string} + * @memberof TelemetryPolicy + */ + public readonly telemetry: string; + + /** + * Creates an instance of TelemetryPolicy. + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @param {ITelemetryOptions} [telemetry] + * @memberof TelemetryPolicy + */ + constructor( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions, + telemetry: string + ) { + super(nextPolicy, options); + this.telemetry = telemetry; + } + + /** + * Sends out request. + * + * @param {WebResource} request + * @returns {Promise} + * @memberof TelemetryPolicy + */ + public async sendRequest( + request: WebResource + ): Promise { + if (isNode) { + if (!request.headers) { + request.headers = new HttpHeaders(); + } + if (!request.headers.get(HeaderConstants.USER_AGENT)) { + request.headers.set(HeaderConstants.USER_AGENT, this.telemetry); + } + } + + return this._nextPolicy.sendRequest(request); + } +} diff --git a/file/lib/policies/TokenCredentialPolicy.ts b/file/lib/policies/TokenCredentialPolicy.ts new file mode 100644 index 0000000..25c1153 --- /dev/null +++ b/file/lib/policies/TokenCredentialPolicy.ts @@ -0,0 +1,72 @@ +import { + HttpHeaders, + RequestPolicy, + RequestPolicyOptions, + WebResource +} from "ms-rest-js"; + +import { TokenCredential } from "../credentials/TokenCredential"; +import { HeaderConstants } from "../utils/constants"; +import { CredentialPolicy } from "./CredentialPolicy"; + +/** + * TokenCredentialPolicy is a policy used to sign HTTP request with a token. + * Such as an OAuth bearer token. + * + * @export + * @class TokenCredentialPolicy + * @extends {CredentialPolicy} + */ +export class TokenCredentialPolicy extends CredentialPolicy { + /** + * The value of token. + * + * @type {TokenCredential} + * @memberof TokenCredentialPolicy + */ + public readonly tokenCredential: TokenCredential; + + /** + * Token authorization scheme, default header is "Bearer". + * + * @type {string} + * @memberof TokenCredentialPolicy + */ + public readonly authorizationScheme: string; + + /** + * Creates an instance of TokenCredentialPolicy. + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @param {TokenCredential} tokenCredential + * @memberof TokenCredentialPolicy + */ + constructor( + nextPolicy: RequestPolicy, + options: RequestPolicyOptions, + tokenCredential: TokenCredential + ) { + super(nextPolicy, options); + this.tokenCredential = tokenCredential; + this.authorizationScheme = HeaderConstants.AUTHORIZATION_SCHEME; + } + + /** + * Sign request with token. + * + * @protected + * @param {WebResource} request + * @returns {WebResource} + * @memberof TokenCredentialPolicy + */ + protected signRequest(request: WebResource): WebResource { + if (!request.headers) { + request.headers = new HttpHeaders(); + } + request.headers.set( + HeaderConstants.AUTHORIZATION, + `${this.authorizationScheme} ${this.tokenCredential.token}` + ); + return request; + } +} diff --git a/file/lib/policies/UniqueRequestIDPolicy.ts b/file/lib/policies/UniqueRequestIDPolicy.ts new file mode 100644 index 0000000..1c6f049 --- /dev/null +++ b/file/lib/policies/UniqueRequestIDPolicy.ts @@ -0,0 +1,48 @@ +import { + BaseRequestPolicy, + generateUuid, + HttpOperationResponse, + RequestPolicy, + RequestPolicyOptions, + WebResource +} from "ms-rest-js"; + +import { HeaderConstants } from "../utils/constants"; + +/** + * UniqueRequestIDPolicy generates an UUID as x-ms-request-id header value. + * + * @class UniqueRequestIDPolicy + * @extends {BaseRequestPolicy} + */ +export class UniqueRequestIDPolicy extends BaseRequestPolicy { + /** + * Creates an instance of UniqueRequestIDPolicy. + * @param {RequestPolicy} nextPolicy + * @param {RequestPolicyOptions} options + * @memberof UniqueRequestIDPolicy + */ + constructor(nextPolicy: RequestPolicy, options: RequestPolicyOptions) { + super(nextPolicy, options); + } + + /** + * Sends request. + * + * @param {WebResource} request + * @returns {Promise} + * @memberof UniqueRequestIDPolicy + */ + public async sendRequest( + request: WebResource + ): Promise { + if (!request.headers.contains(HeaderConstants.X_MS_CLIENT_REQUEST_ID)) { + request.headers.set( + HeaderConstants.X_MS_CLIENT_REQUEST_ID, + generateUuid() + ); + } + + return this._nextPolicy.sendRequest(request); + } +} diff --git a/file/lib/utils/Batch.ts b/file/lib/utils/Batch.ts new file mode 100644 index 0000000..e4917f1 --- /dev/null +++ b/file/lib/utils/Batch.ts @@ -0,0 +1,185 @@ +// In browser, during webpack or browserify bundling, this module will be replaced by 'events' +// https://github.com/Gozala/events +import { EventEmitter } from "events"; + +/** + * Operation is an async function to be executed and managed by Batch. + */ +export declare type Operation = () => Promise; + +/** + * States for Batch. + * + * @enum {number} + */ +enum BatchStates { + Good, + Error +} + +/** + * 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. + * + * @export + * @class Batch + */ +export class Batch { + /** + * Concurrency. Must be lager than 0. + * + * @type {number} + * @memberof Batch + */ + private concurrency: number; + + /** + * Number of active operations under execution. + * + * @private + * @type {number} + * @memberof Batch + */ + private actives: number = 0; + + /** + * Number of completed operations under execution. + * + * @private + * @type {number} + * @memberof Batch + */ + private completed: number = 0; + + /** + * Offset of next operation to be executed. + * + * @private + * @type {number} + * @memberof Batch + */ + private offset: number = 0; + + /** + * Operation array to be executed. + * + * @private + * @type {Operation[]} + * @memberof Batch + */ + private operations: Operation[] = []; + + /** + * States of Batch. When an error happens, state will turn into error. + * Batch will stop execute left operations. + * + * @private + * @type {BatchStates} + * @memberof Batch + */ + private state: BatchStates = BatchStates.Good; + + /** + * A private emitter used to pass events inside this class. + * + * @private + * @type {EventEmitter} + * @memberof Batch + */ + private emitter: EventEmitter; + + /** + * Creates an instance of Batch. + * @param {number} [concurrency=5] + * @memberof Batch + */ + public constructor(concurrency: number = 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} operation + * @memberof Batch + */ + public addOperation(operation: Operation): void { + 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. + * + * @returns {Promise} + * @memberof Batch + */ + public async do(): Promise { + 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. + * + * @private + * @returns {(Operation | null)} + * @memberof Batch + */ + private nextOperation(): Operation | null { + 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. + * + * @private + * @returns {void} + * @memberof Batch + */ + private parallelExecute(): void { + 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; + } + } + } +} diff --git a/file/lib/utils/BufferScheduler.ts b/file/lib/utils/BufferScheduler.ts new file mode 100644 index 0000000..21a91c5 --- /dev/null +++ b/file/lib/utils/BufferScheduler.ts @@ -0,0 +1,439 @@ +import { EventEmitter } from "events"; +import { Readable } from "stream"; + +/** + * OutgoingHandler is an async function triggered by BufferScheduler. + */ +export declare type OutgoingHandler = ( + buffer: Buffer, + offset?: number +) => Promise; + +/** + * 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 <= 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. Parallelism 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. + * @export + * @class BufferScheduler + */ +export 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. + * + * @private + * @type {number} + * @memberof BufferScheduler + */ + private readonly bufferSize: number; + + /** + * How many buffers can be created or maintained. + * + * @private + * @type {number} + * @memberof BufferScheduler + */ + private readonly maxBuffers: number; + + /** + * A Node.js Readable stream. + * + * @private + * @type {Readable} + * @memberof BufferScheduler + */ + private readonly readable: Readable; + + /** + * OutgoingHandler is an async function triggered by BufferScheduler when there + * are available buffers in outgoing array. + * + * @private + * @type {OutgoingHandler} + * @memberof BufferScheduler + */ + private readonly outgoingHandler: OutgoingHandler; + + /** + * An internal event emitter. + * + * @private + * @type {EventEmitter} + * @memberof BufferScheduler + */ + private readonly emitter: EventEmitter = new EventEmitter(); + + /** + * Concurrency of executing outgoingHandlers. (0 < parallelism <= maxBuffers) + * + * @private + * @type {number} + * @memberof BufferScheduler + */ + private readonly parallelism: number; + + /** + * An internal offset marker to track data offset in bytes of next outgoingHandler. + * + * @private + * @type {number} + * @memberof BufferScheduler + */ + private offset: number = 0; + + /** + * An internal marker to track whether stream is end. + * + * @private + * @type {boolean} + * @memberof BufferScheduler + */ + private isStreamEnd: boolean = false; + + /** + * An internal marker to track whether stream or outgoingHandler returns error. + * + * @private + * @type {boolean} + * @memberof BufferScheduler + */ + private isError: boolean = false; + + /** + * How many handlers are executing. + * + * @private + * @type {number} + * @memberof BufferScheduler + */ + private executingOutgoingHandlers: number = 0; + + /** + * Encoding of the input Readable stream which has string data type instead of Buffer. + * + * @private + * @type {string} + * @memberof BufferScheduler + */ + private encoding?: string; + + /** + * How many buffers have been allocated. + * + * @private + * @type {number} + * @memberof BufferScheduler + */ + private numBuffers: number = 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. + * + * @private + * @type {Buffer[]} + * @memberof BufferScheduler + */ + private unresolvedDataArray: Buffer[] = []; + + /** + * How much data consisted in unresolvedDataArray. + * + * @private + * @type {number} + * @memberof BufferScheduler + */ + private unresolvedLength: number = 0; + + /** + * The array includes all the available buffers can be used to fill data from stream. + * + * @private + * @type {Buffer[]} + * @memberof BufferScheduler + */ + private incoming: Buffer[] = []; + + /** + * The array (queue) includes all the buffers filled from stream data. + * + * @private + * @type {Buffer[]} + * @memberof BufferScheduler + */ + private outgoing: Buffer[] = []; + + /** + * Creates an instance of BufferScheduler. + * + * @param {Readable} readable A Node.js Readable stream + * @param {number} bufferSize Buffer size of every maintained buffer + * @param {number} maxBuffers How many buffers can be allocated + * @param {OutgoingHandler} outgoingHandler An async function scheduled to be + * triggered when a buffer fully filled + * with stream data + * @param {number} parallelism Concurrency of executing outgoingHandlers (>0) + * @param {string} [encoding] [Optional] Encoding of Readable stream when it's a string stream + * @memberof BufferScheduler + */ + constructor( + readable: Readable, + bufferSize: number, + maxBuffers: number, + outgoingHandler: OutgoingHandler, + parallelism: number, + encoding?: string + ) { + 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 (parallelism <= 0) { + throw new RangeError( + `parallelism must be larger than 0, current is ${parallelism}` + ); + } + + this.bufferSize = bufferSize; + this.maxBuffers = maxBuffers; + this.readable = readable; + this.outgoingHandler = outgoingHandler; + this.parallelism = parallelism; + this.encoding = encoding; + } + + /** + * Start the scheduler, will return error when stream of any of the outgoingHandlers + * returns error. + * + * @returns {Promise} + * @memberof BufferScheduler + */ + public async do(): Promise { + 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 + ) { + this.outgoingHandler( + this.shiftBufferFromUnresolvedDataArray(), + this.offset + ) + .then(resolve) + .catch(reject); + } else if (this.unresolvedLength >= this.bufferSize) { + return; + } else { + resolve(); + } + } + }); + }); + } + + /** + * Insert a new data into unresolved array. + * + * @private + * @param {Buffer} data + * @memberof BufferScheduler + */ + private appendUnresolvedData(data: Buffer) { + 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. + * + * @private + * @returns {Buffer} + * @memberof BufferScheduler + */ + private shiftBufferFromUnresolvedDataArray(): Buffer { + if (this.unresolvedLength >= this.bufferSize) { + if (this.bufferSize === this.unresolvedDataArray[0].length) { + this.unresolvedLength -= this.bufferSize; + return this.unresolvedDataArray.shift()!; + } + + // Lazy concat because Buffer.concat highly drops performance + let merged = Buffer.concat( + this.unresolvedDataArray, + this.unresolvedLength + ); + const buffer = merged.slice(0, this.bufferSize); + merged = merged.slice(this.bufferSize); + this.unresolvedDataArray = [merged]; + this.unresolvedLength -= buffer.length; + return buffer; + } else if (this.unresolvedLength > 0) { + const merged = Buffer.concat( + this.unresolvedDataArray, + this.unresolvedLength + ); + this.unresolvedDataArray = []; + this.unresolvedLength = 0; + return merged; + } else { + return Buffer.allocUnsafe(0); + } + } + + /** + * 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. + * + * @private + * @returns {boolean} Return false when buffers in incoming are not enough, else true. + * @memberof BufferScheduler + */ + private resolveData(): boolean { + while (this.unresolvedLength >= this.bufferSize) { + let buffer: Buffer; + + if (this.incoming.length > 0) { + buffer = this.incoming.shift()!; + } else { + if (this.numBuffers < this.maxBuffers) { + buffer = Buffer.allocUnsafe(this.bufferSize); + this.numBuffers++; + } else { + // No available buffer, wait for buffer returned + return false; + } + } + + buffer.fill(this.shiftBufferFromUnresolvedDataArray()); + this.outgoing.push(buffer); + this.triggerOutgoingHandlers(); + } + return true; + } + + /** + * Try to trigger a outgoing handler for every buffer in outgoing. Stop when + * parallelism reaches. + * + * @private + * @memberof BufferScheduler + */ + private async triggerOutgoingHandlers() { + let buffer: Buffer | undefined; + do { + if (this.executingOutgoingHandlers >= this.parallelism) { + return; + } + + buffer = this.outgoing.shift(); + if (buffer) { + this.triggerOutgoingHandler(buffer); + } + } while (buffer); + } + + /** + * Trigger a outgoing handler for a buffer shifted from outgoing. + * + * @private + * @param {Buffer} buffer + * @returns {Promise} + * @memberof BufferScheduler + */ + private async triggerOutgoingHandler(buffer: Buffer): Promise { + const bufferLength = buffer.length; + + this.executingOutgoingHandlers++; + this.offset += bufferLength; + + try { + await this.outgoingHandler(buffer, 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. + * + * @private + * @param {Buffer} buffer + * @memberof BufferScheduler + */ + private reuseBuffer(buffer: Buffer) { + this.incoming.push(buffer); + if (!this.isError && this.resolveData() && !this.isStreamEnd) { + this.readable.resume(); + } + } +} diff --git a/file/lib/utils/constants.ts b/file/lib/utils/constants.ts new file mode 100644 index 0000000..76f1f3b --- /dev/null +++ b/file/lib/utils/constants.ts @@ -0,0 +1,47 @@ +export const SDK_VERSION: string = "10.1.0-preview"; +export const SERVICE_VERSION: string = "2018-03-28"; + +export const BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES: number = 256 * 1024 * 1024; // 256MB +export const BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES: number = 100 * 1024 * 1024; // 100MB +export const BLOCK_BLOB_MAX_BLOCKS: number = 50000; +export const BLOB_DEFAULT_DOWNLOAD_BLOCK_BYTES: number = 4 * 1024 * 1024; // 4MB + +export const URLConstants = { + Parameters: { + FORCE_BROWSER_NO_CACHE: "_", + SIGNATURE: "sig", + SNAPSHOT: "snapshot", + TIMEOUT: "timeout" + } +}; + +export const HTTPURLConnection = { + HTTP_CONFLICT: 409, + HTTP_NOT_FOUND: 404, + HTTP_PRECON_FAILED: 412, + HTTP_RANGE_NOT_SATISFIABLE: 416 +}; + +export const HeaderConstants = { + AUTHORIZATION: "authorization", + AUTHORIZATION_SCHEME: "Bearer", + CONTENT_ENCODING: "content-encoding", + CONTENT_LANGUAGE: "content-language", + CONTENT_LENGTH: "content-length", + CONTENT_MD5: "content-md5", + CONTENT_TYPE: "content-type", + COOKIE: "Cookie", + 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", + USER_AGENT: "User-Agent", + X_MS_CLIENT_REQUEST_ID: "x-ms-client-request-id", + X_MS_DATE: "x-ms-date" +}; + +export const ETagNone = ""; +export const ETagAny = "*"; diff --git a/file/lib/utils/utils.browser.ts b/file/lib/utils/utils.browser.ts new file mode 100644 index 0000000..51d2624 --- /dev/null +++ b/file/lib/utils/utils.browser.ts @@ -0,0 +1,17 @@ +/** + * Convert a Browser Blob object into ArrayBuffer. + * + * @export + * @param {Blob} blob + * @returns {Promise} + */ +export async function blobToArrayBuffer(blob: Blob): Promise { + const fileReader = new FileReader(); + return new Promise((resolve, reject) => { + fileReader.onloadend = (ev: any) => { + resolve(ev.target!.result); + }; + fileReader.onerror = reject; + fileReader.readAsArrayBuffer(blob); + }); +} diff --git a/file/lib/utils/utils.common.ts b/file/lib/utils/utils.common.ts new file mode 100644 index 0000000..3f9fde7 --- /dev/null +++ b/file/lib/utils/utils.common.ts @@ -0,0 +1,225 @@ +import { isNode, URLBuilder } from "ms-rest-js"; + +/** + * Append a string to URL path. Will remove duplicated "/" in front of the string + * when URL path ends with a "/". + * + * @export + * @param {string} url Source URL string + * @param {string} name String to be appended to URL + * @returns {string} An updated URL string + */ +export function appendToURLPath(url: string, name: string): string { + const urlParsed = URLBuilder.parse(url); + + let path = urlParsed.getPath(); + path = path + ? path.endsWith("/") + ? `${path}${name}` + : `${path}/${name}` + : name; + urlParsed.setPath(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. + * + * @export + * @param {string} url Source URL string + * @param {string} name Parameter name + * @param {string} [value] Parameter value + * @returns {string} An updated URL string + */ +export function setURLParameter( + url: string, + name: string, + value?: string +): string { + const urlParsed = URLBuilder.parse(url); + urlParsed.setQueryParameter(name, value); + return urlParsed.toString(); +} + +/** + * Get URL parameter by name. + * + * @export + * @param {string} url + * @param {string} name + * @returns {(string | string[] | undefined)} + */ +export function getURLParameter( + url: string, + name: string +): string | string[] | undefined { + const urlParsed = URLBuilder.parse(url); + return urlParsed.getQueryParameterValue(name); +} + +/** + * Set URL host. + * + * @export + * @param {string} url Source URL string + * @param {string} host New host string + * @returns An updated URL string + */ +export function setURLHost(url: string, host: string): string { + const urlParsed = URLBuilder.parse(url); + urlParsed.setHost(host); + return urlParsed.toString(); +} + +/** + * Get URL path from an URL string. + * + * @export + * @param {string} url Source URL string + * @returns {(string | undefined)} + */ +export function getURLPath(url: string): string | undefined { + const urlParsed = URLBuilder.parse(url); + return urlParsed.getPath(); +} + +/** + * Get URL query key value pairs from an URL string. + * + * @export + * @param {string} url + * @returns {{[key: string]: string}} + */ +export function getURLQueries(url: string): { [key: string]: string } { + let queryString = URLBuilder.parse(url).getQuery(); + if (!queryString) { + return {}; + } + + queryString = queryString.trim(); + queryString = queryString.startsWith("?") + ? queryString.substr(1) + : queryString; + + let querySubStrings: string[] = queryString.split("&"); + querySubStrings = querySubStrings.filter((value: string) => { + const indexOfEqual = value.indexOf("="); + const lastIndexOfEqual = value.lastIndexOf("="); + return ( + indexOfEqual > 0 && + indexOfEqual === lastIndexOfEqual && + lastIndexOfEqual < value.length - 1 + ); + }); + + const queries: { [key: string]: string } = {}; + for (const querySubString of querySubStrings) { + const splitResults = querySubString.split("="); + const key: string = splitResults[0]; + const value: string = splitResults[1]; + queries[key] = value; + } + + return queries; +} + +/** + * Rounds a date off to seconds. + * + * @export + * @param {Date} date Input date + * @returns {string} Date string in ISO8061 format, with no milliseconds component + */ +export function truncatedISO8061Date(date: Date): string { + const dateString = date.toISOString(); + return dateString.substring(0, dateString.length - 1) + "0000" + "Z"; +} + +/** + * Base64 encode. + * + * @export + * @param {string} content + * @returns {string} + */ +export function base64encode(content: string): string { + return !isNode ? btoa(content) : Buffer.from(content).toString("base64"); +} + +/** + * Base64 decode. + * + * @export + * @param {string} encodedString + * @returns {string} + */ +export function base64decode(encodedString: string): string { + return !isNode + ? atob(encodedString) + : Buffer.from(encodedString, "base64").toString(); +} + +/** + * Generate a 64 bytes base64 block ID string. + * + * @export + * @param {number} blockIndex + * @returns {string} + */ +export function generateBlockID( + blockIDPrefix: string, + blockIndex: number +): string { + // 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(res); +} + +/** + * String.prototype.padStart() + * + * @export + * @param {string} currentString + * @param {number} targetLength + * @param {string} [padString=" "] + * @returns {string} + */ +export function padStart( + currentString: string, + targetLength: number, + padString: string = " " +): string { + 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; + } +} diff --git a/file/lib/utils/utils.node.ts b/file/lib/utils/utils.node.ts new file mode 100644 index 0000000..74f04f0 --- /dev/null +++ b/file/lib/utils/utils.node.ts @@ -0,0 +1,62 @@ +/** + * Reads a readable stream into buffer. Fill the buffer from offset to end. + * + * @export + * @param {NodeJS.ReadableStream} stream A Node.js Readable stream + * @param {Buffer} buffer Buffer to be filled, length must >= offset + * @param {number} offset From which position in the buffer to be filled, inclusive + * @param {number} end To which position in the buffer to be filled, exclusive + * @param {string} [encoding] Encoding of the Readable stream + * @returns {Promise} + */ +export async function streamToBuffer( + stream: NodeJS.ReadableStream, + buffer: Buffer, + offset: number, + end: number, + encoding?: string +): Promise { + let pos = 0; // Position in stream + const count = end - offset; // Total amount of data needed in stream + + return new Promise((resolve, reject) => { + stream.on("readable", () => { + if (pos >= count) { + resolve(); + return; + } + + let chunk = stream.read(); + if (!chunk) { + return; + } + 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; + }); + + stream.on("end", () => { + if (pos < count) { + reject( + new Error( + `Stream drains before getting enough data needed. Data read: ${pos}, data need: ${count}` + ) + ); + } + resolve(); + }); + + stream.on("error", reject); + }); +} diff --git a/file/package-lock.json b/file/package-lock.json new file mode 100644 index 0000000..6950569 --- /dev/null +++ b/file/package-lock.json @@ -0,0 +1,5689 @@ +{ + "name": "@azure/storage-file", + "version": "10.0.0-preview", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@types/body-parser": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz", + "integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", + "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", + "requires": { + "@types/node": "*" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/events": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==" + }, + "@types/express": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.16.0.tgz", + "integrity": "sha512-TtPEYumsmSTtTetAPXlJVf3kEqb6wZK0bZojpJQrnD/djV4q1oB6QQ8aKvKqwNPACoe02GNiy5zDzcYivR5Z2w==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz", + "integrity": "sha512-lTeoCu5NxJU4OD9moCgm0ESZzweAx0YqsAcab6OB0EB3+As1OaHtKnaGJvcngQxYsi9UNv0abn4/DRavrRxt4w==", + "requires": { + "@types/events": "*", + "@types/node": "*", + "@types/range-parser": "*" + } + }, + "@types/form-data": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz", + "integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/mime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", + "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==" + }, + "@types/mocha": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz", + "integrity": "sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww==", + "dev": true + }, + "@types/node": { + "version": "10.12.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.3.tgz", + "integrity": "sha512-sfGmOtSMSbQ/AKG8V9xD1gmjquC9awIIZ/Kj309pHb2n3bcRAcGMQv5nJ6gCXZVsneGE4+ve8DXKRCsrg3TFzg==" + }, + "@types/range-parser": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.2.tgz", + "integrity": "sha512-HtKGu+qG1NPvYe1z7ezLsyIaXYyi8SoAVqWDZgDQ8dLrsZvSzUNCwZyfX33uhWxL/SU0ZDQZ3nwZ0nimt507Kw==" + }, + "@types/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, + "@types/uuid": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz", + "integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==", + "requires": { + "@types/node": "*" + } + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "ansi-colors": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "dev": true, + "requires": { + "buffer-equal": "^1.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "dev": true, + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "dev": true, + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "dev": true + }, + "array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "dev": true, + "requires": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "requires": { + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true + }, + "array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "requires": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async-array-reduce": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/async-array-reduce/-/async-array-reduce-0.2.1.tgz", + "integrity": "sha1-yL4BCitc0A3qlsgRFgNGk9/dgtE=", + "dev": true + }, + "async-done": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.1.tgz", + "integrity": "sha512-R1BaUeJ4PMoLNJuk+0tLJgjmEqVsdN118+Z8O+alhnQDQgy0kmD5Mqi0DNEmMx2LM0Ed5yekKu+ZXYvIHceicg==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^1.0.7", + "stream-exhaust": "^1.0.1" + } + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true + }, + "async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "dev": true, + "requires": { + "async-done": "^1.2.2" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "axios": { + "version": "0.18.0", + "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, + "bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "dev": true, + "requires": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "binary-extensions": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", + "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "dev": true + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", + "dev": true + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chokidar": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", + "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.2.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "lodash.debounce": "^4.0.8", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.5" + } + }, + "circular-json": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", + "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "cloneable-readable": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", + "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "dev": true, + "requires": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colors": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz", + "integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ==", + "dev": true + }, + "combine-lists": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", + "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", + "dev": true, + "requires": { + "lodash": "^4.5.0" + } + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.15.1", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-props": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "dev": true, + "requires": { + "each-props": "^1.3.0", + "is-plain-object": "^2.0.1" + } + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "^0.10.9" + } + }, + "date-format": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", + "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dev": true, + "requires": { + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "duplexify": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", + "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "edge-launcher": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/edge-launcher/-/edge-launcher-1.2.2.tgz", + "integrity": "sha1-60Cq+9Bnpup27/+rBke81VCbN7I=", + "dev": true + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es5-ext": { + "version": "0.10.46", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz", + "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "1" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-promise": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", + "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==", + "dev": true + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "estree-walker": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz", + "integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "dev": true + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==" + }, + "expand-braces": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", + "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", + "dev": true, + "requires": { + "array-slice": "^0.2.3", + "array-unique": "^0.2.1", + "braces": "^0.1.2" + }, + "dependencies": { + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", + "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", + "dev": true, + "requires": { + "expand-range": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-range": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", + "dev": true, + "requires": { + "is-number": "^0.1.1", + "repeat-string": "^0.2.2" + }, + "dependencies": { + "is-number": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", + "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", + "dev": true + }, + "repeat-string": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", + "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", + "dev": true + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fancy-log": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", + "dev": true, + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "time-stamp": "^1.0.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + } + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "fined": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", + "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz", + "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=", + "dev": true + }, + "flush-write-stream": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", + "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "follow-redirects": { + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.9.tgz", + "integrity": "sha512-Bh65EZI/RU8nx0wbYF9shkFZlqLP+6WT/5FnA3cE/djNSuKNHJEinGGZgu/cQEkeeb2GdFOgenAmn8qaqYke2w==", + "requires": { + "debug": "=3.1.0" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "^1.0.0" + } + }, + "fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", + "dev": true + }, + "fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", + "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.21", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "^2.1.0" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.1.10", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true, + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + } + }, + "glob-watcher": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.1.tgz", + "integrity": "sha512-fK92r2COMC199WCyGUblrZKhjra3cyVMDiypDdqg1vsSDmexnbYivK1kNR4QItiNXLKmGlqan469ks67RtNa2g==", + "dev": true, + "requires": { + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "just-debounce": "^1.0.0", + "object.defaults": "^1.1.0" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "glogg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz", + "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==", + "dev": true, + "requires": { + "sparkles": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "gulp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.0.tgz", + "integrity": "sha1-lXZsYB2t5Kd+0+eyttwDiBtZY2Y=", + "dev": true, + "requires": { + "glob-watcher": "^5.0.0", + "gulp-cli": "^2.0.0", + "undertaker": "^1.0.0", + "vinyl-fs": "^3.0.0" + }, + "dependencies": { + "gulp-cli": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.0.1.tgz", + "integrity": "sha512-RxujJJdN8/O6IW2nPugl7YazhmrIEjmiVfPKrWt68r71UCaLKS71Hp0gpKT+F6qOUFtr7KqtifDKaAJPRVvMYQ==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.1.0", + "isobject": "^3.0.1", + "liftoff": "^2.5.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.0.1", + "yargs": "^7.1.0" + } + } + } + }, + "gulp-zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gulp-zip/-/gulp-zip-4.2.0.tgz", + "integrity": "sha512-I+697f6jf+PncdTrqfuwoauxgnLG1yHRg3vlmvDgmJuEnlEHy4meBktJ/oHgfyg4tp6X25wuZqUOraVeVg97wQ==", + "dev": true, + "requires": { + "get-stream": "^3.0.0", + "plugin-error": "^0.1.2", + "through2": "^2.0.1", + "vinyl": "^2.1.0", + "yazl": "^2.1.0" + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "requires": { + "glogg": "^1.0.0" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-glob": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-0.1.1.tgz", + "integrity": "sha1-omHEwqbGZ+DHe3AKfyl8Oe86pYk=", + "dev": true, + "requires": { + "is-glob": "^2.0.1" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "http-proxy": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "dev": true, + "requires": { + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "jest-worker": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz", + "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=", + "dev": true, + "requires": { + "merge-stream": "^1.0.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "just-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", + "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=", + "dev": true + }, + "karma": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-3.1.1.tgz", + "integrity": "sha512-NetT3wPCQMNB36uiL9LLyhrOt8SQwrEKt0xD3+KpTCfm0VxVyUJdPL5oTq2Ic5ouemgL/Iz4wqXEbF3zea9kQQ==", + "dev": true, + "requires": { + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "chokidar": "^2.0.3", + "colors": "^1.1.0", + "combine-lists": "^1.0.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "expand-braces": "^0.1.1", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.4", + "log4js": "^3.0.0", + "mime": "^2.3.1", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "2.1.1", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "useragent": "2.2.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "karma-chrome-launcher": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "dev": true, + "requires": { + "fs-access": "^1.0.0", + "which": "^1.2.1" + } + }, + "karma-edge-launcher": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/karma-edge-launcher/-/karma-edge-launcher-0.4.2.tgz", + "integrity": "sha512-YAJZb1fmRcxNhMIWYsjLuxwODBjh2cSHgTW/jkVmdpGguJjLbs9ZgIK/tEJsMQcBLUkO+yO4LBbqYxqgGW2HIw==", + "dev": true, + "requires": { + "edge-launcher": "1.2.2" + } + }, + "karma-env-preprocessor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/karma-env-preprocessor/-/karma-env-preprocessor-0.1.1.tgz", + "integrity": "sha1-u+jIfVnADtt2BwvTwxtLOdXcfhU=", + "dev": true + }, + "karma-firefox-launcher": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-1.1.0.tgz", + "integrity": "sha512-LbZ5/XlIXLeQ3cqnCbYLn+rOVhuMIK9aZwlP6eOLGzWdo1UVp7t6CN3DP4SafiRLjexKwHeKHDm0c38Mtd3VxA==", + "dev": true + }, + "karma-ie-launcher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/karma-ie-launcher/-/karma-ie-launcher-1.0.0.tgz", + "integrity": "sha1-SXmGhCxJAZA0bNifVJTKmDDG1Zw=", + "dev": true, + "requires": { + "lodash": "^4.6.1" + } + }, + "karma-mocha": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-1.3.0.tgz", + "integrity": "sha1-7qrH/8DiAetjxGdEDStpx883eL8=", + "dev": true, + "requires": { + "minimist": "1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "karma-mocha-reporter": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/karma-mocha-reporter/-/karma-mocha-reporter-2.2.5.tgz", + "integrity": "sha1-FRIAlejtgZGG5HoLAS8810GJVWA=", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "log-symbols": "^2.1.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "dev": true, + "requires": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + } + }, + "lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", + "dev": true, + "requires": { + "set-getter": "^0.1.0" + } + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true, + "requires": { + "readable-stream": "^2.0.5" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "dev": true, + "requires": { + "flush-write-stream": "^1.0.2" + } + }, + "liftoff": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", + "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "findup-sync": "^2.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "log4js": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-3.0.6.tgz", + "integrity": "sha512-ezXZk6oPJCWL483zj64pNkMuY/NcRX5MPiB0zE6tjZM137aeusrOnW1ecxgF9cmwMWkBMhjteQxBPoZBh9FDxQ==", + "dev": true, + "requires": { + "circular-json": "^0.5.5", + "date-format": "^1.2.0", + "debug": "^3.1.0", + "rfdc": "^1.1.2", + "streamroller": "0.7.0" + } + }, + "lru-cache": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", + "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", + "dev": true + }, + "magic-string": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.1.tgz", + "integrity": "sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.1" + } + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "dev": true, + "requires": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + } + }, + "matched": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/matched/-/matched-0.4.4.tgz", + "integrity": "sha1-Vte36xgDPwz5vFLrIJD6x9weifo=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "async-array-reduce": "^0.2.0", + "extend-shallow": "^2.0.1", + "fs-exists-sync": "^0.1.0", + "glob": "^7.0.5", + "has-glob": "^0.1.1", + "is-valid-glob": "^0.3.0", + "lazy-cache": "^2.0.1", + "resolve-dir": "^0.1.0" + }, + "dependencies": { + "expand-tilde": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", + "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=", + "dev": true, + "requires": { + "os-homedir": "^1.0.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "global-modules": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", + "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=", + "dev": true, + "requires": { + "global-prefix": "^0.1.4", + "is-windows": "^0.2.0" + } + }, + "global-prefix": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", + "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.0", + "ini": "^1.3.4", + "is-windows": "^0.2.0", + "which": "^1.2.12" + } + }, + "is-valid-glob": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz", + "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=", + "dev": true + }, + "is-windows": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", + "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=", + "dev": true + }, + "resolve-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", + "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=", + "dev": true, + "requires": { + "expand-tilde": "^1.2.2", + "global-modules": "^0.2.3" + } + } + } + }, + "math-random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mime": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", + "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", + "dev": true + }, + "mime-db": { + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" + }, + "mime-types": { + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "requires": { + "mime-db": "~1.37.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "ms-rest-js": { + "version": "0.22.425", + "resolved": "https://registry.npmjs.org/ms-rest-js/-/ms-rest-js-0.22.425.tgz", + "integrity": "sha512-PM9l0Si+T3kFxce8hwB/LlCxPJSHwSlFUSpjdJHzPvF+2w8lw7huE/FCPnRfdaUm7IikQESkJhydnbqX6g2OuQ==", + "requires": { + "@types/express": "^4.11.1", + "@types/form-data": "^2.2.1", + "@types/node": "^9.4.6", + "@types/uuid": "^3.4.3", + "axios": "^0.18.0", + "form-data": "^2.3.2", + "tough-cookie": "^2.4.3", + "tslib": "^1.9.2", + "uuid": "^3.2.1", + "xml2js": "^0.4.19" + }, + "dependencies": { + "@types/node": { + "version": "9.6.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.36.tgz", + "integrity": "sha512-Fbw+AdRLL01vv7Rk7bYaNPecqmKoinJHGbpKnDpbUZmUj/0vj3nLqPQ4CNBzr3q2zso6Cq/4jHoCAdH78fvJrw==" + } + } + }, + "mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true + }, + "nan": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", + "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "now-and-later": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz", + "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=", + "dev": true, + "requires": { + "once": "^1.3.2" + } + }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "dev": true, + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + } + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opn": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", + "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", + "dev": true, + "requires": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "dependencies": { + "arr-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + } + }, + "arr-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", + "dev": true + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", + "dev": true, + "requires": { + "kind-of": "^1.1.0" + } + }, + "kind-of": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", + "dev": true + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + } + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + } + }, + "remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "dev": true, + "requires": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, + "replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "dev": true, + "requires": { + "value-or-function": "^3.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rfdc": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.2.tgz", + "integrity": "sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA==", + "dev": true + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "rollup": { + "version": "0.65.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.65.2.tgz", + "integrity": "sha512-BbXOrpxVbx0MpElI6vVLR2B6vnWHvYU/QAMw3GcEXvs601bvgrozuaW30cnvt43B96a6DeoYA0i9T5THanN+Rw==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "@types/node": "*" + } + }, + "rollup-plugin-commonjs": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-9.2.0.tgz", + "integrity": "sha512-0RM5U4Vd6iHjL6rLvr3lKBwnPsaVml+qxOGaaNUWN1lSq6S33KhITOfHmvxV3z2vy9Mk4t0g4rNlVaJJsNQPWA==", + "dev": true, + "requires": { + "estree-walker": "^0.5.2", + "magic-string": "^0.25.1", + "resolve": "^1.8.1", + "rollup-pluginutils": "^2.3.3" + } + }, + "rollup-plugin-multi-entry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-multi-entry/-/rollup-plugin-multi-entry-2.0.2.tgz", + "integrity": "sha512-TY72fCVJvcEAQBpBzkXykoYQx2fz0B20EVtcbh0WZaYr5eBu3U1dRPzgMt6aO8MePWWOdcmgoBtG6PhmYJr4Ew==", + "dev": true, + "requires": { + "matched": "^0.4.4" + } + }, + "rollup-plugin-node-resolve": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.4.0.tgz", + "integrity": "sha512-PJcd85dxfSBWih84ozRtBkB731OjXk0KnzN0oGp7WOWcarAFkVa71cV5hTJg2qpVsV2U8EUwrzHP3tvy9vS3qg==", + "dev": true, + "requires": { + "builtin-modules": "^2.0.0", + "is-module": "^1.0.0", + "resolve": "^1.1.6" + }, + "dependencies": { + "builtin-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-2.0.0.tgz", + "integrity": "sha512-3U5kUA5VPsRUA3nofm/BXX7GVHKfxz0hOBAPxXrIvHzlDRkQVqEn6yi8QJegxl4LzOHLdvb7XF5dVawa/VVYBg==", + "dev": true + } + } + }, + "rollup-plugin-replace": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.1.0.tgz", + "integrity": "sha512-SxrAIgpH/B5/W4SeULgreOemxcpEgKs2gcD42zXw50bhqGWmcnlXneVInQpAqzA/cIly4bJrOpeelmB9p4YXSQ==", + "dev": true, + "requires": { + "magic-string": "^0.25.1", + "minimatch": "^3.0.2", + "rollup-pluginutils": "^2.0.1" + } + }, + "rollup-plugin-shim": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-shim/-/rollup-plugin-shim-1.0.0.tgz", + "integrity": "sha512-rZqFD43y4U9nSqVq3iyWBiDwmBQJY8Txi04yI9jTKD3xcl7CbFjh1qRpQshUB3sONLubDzm7vJiwB+1MEGv67w==", + "dev": true + }, + "rollup-plugin-uglify": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-uglify/-/rollup-plugin-uglify-5.0.2.tgz", + "integrity": "sha512-CRRyMgKjTwTx1GXnn+v1VYV+6De5NyPB1UBStsQIQ+asrxvP7dK43cg2pf1vyFNr/NIHGvfYAR9Yo4j+5ZMQsw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "jest-worker": "^23.2.0", + "uglify-js": "^3.4.8" + } + }, + "rollup-plugin-visualizer": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-0.9.2.tgz", + "integrity": "sha512-EHXHLp9Q8v5QdRTSjgio4Alr2MKxCJroLhJunmcH+pWAM5869nI5mdWjk2jp64rjxzEahrMYmfF/G5sbTHIhKw==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1", + "opn": "^5.3.0", + "source-map": "^0.7.3", + "typeface-oswald": "0.0.54" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "rollup-pluginutils": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.3.3.tgz", + "integrity": "sha512-2XZwja7b6P5q4RZ5FhyX1+f46xi1Z3qBKigLRZ6VTZjwbN0K1IFGMlwm06Uu0Emcre2Z63l77nq/pzn+KxIEoA==", + "dev": true, + "requires": { + "estree-walker": "^0.5.2", + "micromatch": "^2.3.11" + }, + "dependencies": { + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "^2.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "dev": true, + "requires": { + "sver-compat": "^1.5.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-getter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", + "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", + "dev": true, + "requires": { + "to-object-path": "^0.3.0" + } + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "sourcemap-codec": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.3.tgz", + "integrity": "sha512-vFrY/x/NdsD7Yc8mpTJXuao9S8lq08Z/kOITHz6b7YbfI9xL8Spe5EvSQUHOI7SbpY8bRPr0U3kKSsPuqEGSfA==", + "dev": true + }, + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true + }, + "spdx-correct": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", + "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", + "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "streamroller": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", + "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "dev": true, + "requires": { + "date-format": "^1.2.0", + "debug": "^3.1.0", + "mkdirp": "^0.5.1", + "readable-stream": "^2.3.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "dev": true, + "requires": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-filter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz", + "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", + "dev": true, + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "dev": true, + "requires": { + "through2": "^2.0.3" + } + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typeface-oswald": { + "version": "0.0.54", + "resolved": "https://registry.npmjs.org/typeface-oswald/-/typeface-oswald-0.0.54.tgz", + "integrity": "sha512-U1WMNp4qfy4/3khIfHMVAIKnNu941MXUfs3+H9R8PFgnoz42Hh9pboSFztWr86zut0eXC8byalmVhfkiKON/8Q==", + "dev": true + }, + "typescript": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz", + "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==", + "dev": true + }, + "uglify-js": { + "version": "3.4.9", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", + "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "dev": true, + "requires": { + "commander": "~2.17.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true + }, + "undertaker": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.0.tgz", + "integrity": "sha1-M52kZGJS0ILcN45wgGcpl1DhG0k=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + } + }, + "undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unique-stream": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz", + "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", + "dev": true, + "requires": { + "json-stable-stringify": "^1.0.0", + "through2-filter": "^2.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "dev": true + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "useragent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz", + "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", + "dev": true, + "requires": { + "lru-cache": "2.2.x", + "tmp": "0.0.x" + } + }, + "util": { + "version": "0.10.3", + "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "v8flags": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.1.tgz", + "integrity": "sha512-iw/1ViSEaff8NJ3HLyEjawk/8hjJib3E7pvG4pddVXfUg1983s3VGsiClDjhK64MQVDGqc1Q8r18S4VKQZS9EQ==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "dev": true + }, + "vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + } + }, + "vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "requires": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + } + }, + "vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "dev": true, + "requires": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + } + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + }, + "yazl": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.4.3.tgz", + "integrity": "sha1-7CblzIfVYBud+EMtvdPNLlFzoHE=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + } + } +} diff --git a/file/package.json b/file/package.json new file mode 100644 index 0000000..dbb863d --- /dev/null +++ b/file/package.json @@ -0,0 +1,83 @@ +{ + "name": "@azure/storage-file", + "version": "10.0.0-preview", + "description": "Microsoft Azure Storage SDK for JavaScript - File", + "main": "./dist/index.js", + "module": "./dist-esm/lib/index.js", + "browser": { + "./dist/index.js": "./browser/azure-storage.file.min.js", + "./dist-esm/lib/index.js": "./dist-esm/lib/index.browser.js", + "./dist-esm/test/utils/index.js": "./dist-esm/test/utils/index.browser.js", + "os": false, + "process": false + }, + "types": "./typings/lib/index.d.ts", + "engines": { + "node": ">=6.5.0" + }, + "dependencies": { + "events": "3.0.0", + "ms-rest-js": "0.22.425", + "tslib": "^1.9.3" + }, + "devDependencies": { + "@types/mocha": "^5.2.5", + "@types/node": "^10.12.3", + "assert": "^1.4.1", + "es6-promise": "^4.2.4", + "gulp": "^4.0.0", + "gulp-zip": "^4.2.0", + "karma": "^3.0.0", + "karma-chrome-launcher": "^2.2.0", + "karma-edge-launcher": "^0.4.2", + "karma-env-preprocessor": "^0.1.1", + "karma-firefox-launcher": "^1.1.0", + "karma-ie-launcher": "^1.0.0", + "karma-mocha": "^1.3.0", + "karma-mocha-reporter": "^2.2.5", + "mocha": "^5.2.0", + "rimraf": "^2.6.2", + "rollup": "^0.65.2", + "rollup-plugin-commonjs": "^9.1.8", + "rollup-plugin-multi-entry": "^2.0.2", + "rollup-plugin-node-resolve": "^3.4.0", + "rollup-plugin-replace": "^2.0.0", + "rollup-plugin-shim": "^1.0.0", + "rollup-plugin-uglify": "^5.0.2", + "rollup-plugin-visualizer": "^0.9.0", + "ts-node": "^7.0.1", + "typescript": "^3.1.6" + }, + "scripts": { + "test": "npm run test:node && npm run test:browser", + "test:node": "npm run build:test && mocha --no-timeouts dist-test/index.js", + "test:browser": "npm run build:test && karma start --single-run", + "build": "npm run build:es6 && npm run build:nodebrowser && npm run build:browserzip", + "build:test": "rollup -c rollup.test.config.js", + "build:nodebrowser": "rollup -c", + "build:es6": "tsc -p tsconfig.json", + "build:autorest": "autorest ./swagger/README.md --typescript --use=@microsoft.azure/autorest.typescript@2.0.476", + "build:browserzip": "gulp zip", + "clean": "rimraf dist dist-esm dist-test typings temp browser/*.js* browser/*.zip statistics.html" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Azure/azure-storage-js.git" + }, + "keywords": [ + "Azure", + "Storage", + "File", + "Node.js", + "TypeScript", + "JavaScript", + "Browser" + ], + "author": "Microsoft Corporation", + "license": "MIT", + "bugs": { + "url": "https://github.com/Azure/azure-storage-js/issues" + }, + "homepage": "https://github.com/Azure/azure-storage-js#readme", + "sideEffects": false +} diff --git a/file/rollup.config.js b/file/rollup.config.js new file mode 100644 index 0000000..147be53 --- /dev/null +++ b/file/rollup.config.js @@ -0,0 +1,92 @@ +import nodeResolve from "rollup-plugin-node-resolve"; +import { uglify } from "rollup-plugin-uglify"; +import replace from "rollup-plugin-replace"; +import commonjs from "rollup-plugin-commonjs"; +import shim from "rollup-plugin-shim"; +import visualizer from "rollup-plugin-visualizer"; + +const version = require("./package.json").version; +const banner = [ + "/*!", + ` * Azure Storage SDK for JavaScript - File, ${version}`, + " * Copyright (c) Microsoft and contributors. All rights reserved.", + " */" +].join("\n"); + +const nodeRollupConfigFactory = () => { + return { + external: ["ms-rest-js", "crypto", "fs", "events", "os"], + input: "dist-esm/lib/index.js", + output: { + file: "dist/index.js", + format: "cjs", + sourcemap: true + }, + plugins: [nodeResolve(), uglify()] + }; +}; + +const browserRollupConfigFactory = isProduction => { + const browserRollupConfig = { + input: "dist-esm/lib/index.browser.js", + output: { + file: "browser/azure-storage.file.js", + banner: banner, + format: "umd", + name: "azfile", + sourcemap: true + }, + plugins: [ + replace({ + delimiters: ["", ""], + values: { + // replace dynamic checks with if (false) since this is for + // browser only. Rollup's dead code elimination will remove + // any code guarded by if (isNode) { ... } + "if (isNode)": "if (false)" + } + }), + // os is not used by the browser bundle, so just shim it + shim({ + os: ` + export const type = 1; + export const release = 1; + ` + }), + nodeResolve({ + module: true, + browser: true, + preferBuiltins: false + }), + commonjs({ + namedExports: { + events: ["EventEmitter"], + assert: ["ok", "deepEqual", "equal", "fail", "deepStrictEqual"] + } + }) + ] + }; + + if (isProduction) { + browserRollupConfig.output.file = "browser/azure-storage.file.min.js"; + browserRollupConfig.plugins.push( + uglify({ + output: { + preamble: banner + } + }), + visualizer({ + filename: "./statistics.html", + sourcemap: true + }) + ); + } + + return browserRollupConfig; +}; + +export default [ + nodeRollupConfigFactory(), + browserRollupConfigFactory(true), + browserRollupConfigFactory(false) +]; diff --git a/file/rollup.test.config.js b/file/rollup.test.config.js new file mode 100644 index 0000000..6d0809c --- /dev/null +++ b/file/rollup.test.config.js @@ -0,0 +1,16 @@ +import multi from "rollup-plugin-multi-entry"; +import baseConfig from "./rollup.config"; +const [node, browser] = baseConfig; + +node.input = ["dist-esm/test/*.js", "dist-esm/test/node/*.js"]; +node.output.file = "dist-test/index.js"; +node.plugins.unshift(multi()); +node.external.push("assert", "path"); +node.context = "null"; + +browser.input = ["dist-esm/test/*.js", "dist-esm/test/browser/*.js"]; +browser.output.file = "dist-test/index.browser.js"; +browser.plugins.unshift(multi()); +browser.context = "null"; + +export default [node, browser]; diff --git a/file/samples/basic.sample.js b/file/samples/basic.sample.js new file mode 100644 index 0000000..980ae92 --- /dev/null +++ b/file/samples/basic.sample.js @@ -0,0 +1,115 @@ +// Steps to run this sample +// 1. npm install +// 2. Enter your storage account name and shared key in main() + +const { + Aborter, + BlobURL, + BlockBlobURL, + ContainerURL, + ServiceURL, + StorageURL, + SharedKeyCredential, + AnonymousCredential, + TokenCredential +} = require(".."); // Change to "@azure/storage-blob" in your package + +async function main() { + // Enter your storage account name and shared key + const account = "account"; + const accountKey = "accountkey"; + + // Use SharedKeyCredential with storage account and account key + const sharedKeyCredential = new SharedKeyCredential(account, accountKey); + + // Use TokenCredential with OAuth token + const tokenCredential = new TokenCredential("token"); + tokenCredential.token = "renewedToken"; // Renew the token by updating token filed of token credential + + // Use AnonymousCredential when url already includes a SAS signature + const anonymousCredential = new AnonymousCredential(); + + // Use sharedKeyCredential, tokenCredential or AnonymousCredential to create a pipeline + const pipeline = StorageURL.newPipeline(sharedKeyCredential); + + // List containers + const serviceURL = new ServiceURL( + // When using AnonymousCredential, following url should include a valid SAS or support public access + `https://${account}.blob.core.windows.net`, + pipeline + ); + + let marker; + do { + const listContainersResponse = await serviceURL.listContainersSegment( + Aborter.none, + marker + ); + + marker = listContainersResponse.marker; + for (const container of listContainersResponse.containerItems) { + console.log(`Container: ${container.name}`); + } + } while (marker); + + // Create a container + const containerName = `newcontainer${new Date().getTime()}`; + const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + + const createContainerResponse = await containerURL.create(Aborter.none); + console.log( + `Create container ${containerName} successfully`, + createContainerResponse.requestId + ); + + // Create a blob + const content = "hello"; + const blobName = "newblob" + new Date().getTime(); + const blobURL = BlobURL.fromContainerURL(containerURL, blobName); + const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + const uploadBlobResponse = await blockBlobURL.upload( + Aborter.none, + content, + content.length + ); + console.log( + `Upload block blob ${blobName} successfully`, + uploadBlobResponse.requestId + ); + + // List blobs + do { + const listBlobsResponse = await containerURL.listBlobFlatSegment( + Aborter.none, + marker + ); + + marker = listBlobsResponse.marker; + for (const blob of listBlobsResponse.segment.blobItems) { + console.log(`Blob: ${blob.name}`); + } + } while (marker); + + // Get blob content from position 0 to the end + // In Node.js, get downloaded data by accessing downloadBlockBlobResponse.readableStreamBody + // In browsers, get downloaded data by accessing downloadBlockBlobResponse.blobBody + const downloadBlockBlobResponse = await blobURL.download(Aborter.none, 0); + console.log( + "Downloaded blob content", + downloadBlockBlobResponse.readableStreamBody.read(content.length).toString() + ); + + // Delete container + await containerURL.delete(Aborter.none); + + console.log("deleted container"); +} + +// An async method returns a Promise object, which is compatible with then().catch() coding style. +main() + .then(() => { + console.log("Successfully executed sample."); + }) + .catch(err => { + console.log(err.message); + }); \ No newline at end of file diff --git a/file/samples/highlevel.sample.js b/file/samples/highlevel.sample.js new file mode 100644 index 0000000..be7e3d8 --- /dev/null +++ b/file/samples/highlevel.sample.js @@ -0,0 +1,112 @@ +// Steps to run this sample +// 1. npm install +// 2. Enter your storage account name, SAS and a path pointing to local file in main() + +const fs = require("fs"); +const { + AnonymousCredential, + uploadBrowserDataToBlockBlob, + downloadBlobToBuffer, + uploadFileToBlockBlob, + uploadStreamToBlockBlob, + Aborter, + BlobURL, + BlockBlobURL, + ContainerURL, + ServiceURL, + StorageURL +} = require(".."); // Change to "@azure/storage-blob" in your package + +async function main() { + // Fill in following settings before running this sample + const account = "account"; + const accountSas = "accountSas"; + const localFilePath = "localFilePath"; + + const pipeline = StorageURL.newPipeline(new AnonymousCredential(), { + // httpClient: MyHTTPClient, // A customized HTTP client implementing IHTTPClient interface + // logger: MyLogger, // A customized logger implementing IHTTPPipelineLogger interface + retryOptions: { maxTries: 4 }, // Retry options + telemetry: { value: "HighLevelSample V1.0.0" } // Customized telemetry string + }); + + const serviceURL = new ServiceURL( + `https://${account}.blob.core.windows.net${accountSas}`, + pipeline + ); + + // Create a container + const containerName = `newcontainer${new Date().getTime()}`; + const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + + // Create a blob + const blobName = "newblob" + new Date().getTime(); + const blobURL = BlobURL.fromContainerURL(containerURL, blobName); + const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + + // Parallel uploading with uploadFileToBlockBlob in Node.js runtime + // uploadFileToBlockBlob is only available in Node.js + await uploadFileToBlockBlob(Aborter.none, localFilePath, blockBlobURL, { + blockSize: 4 * 1024 * 1024, // 4MB block size + parallelism: 20, // 20 concurrency + progress: ev => console.log(ev) + }); + console.log("uploadFileToBlockBlob success"); + + // Parallel uploading a Readable stream with uploadStreamToBlockBlob in Node.js runtime + // uploadStreamToBlockBlob is only available in Node.js + await uploadStreamToBlockBlob( + Aborter.timeout(30 * 60 * 60 * 1000), // Abort uploading with timeout in 30mins + fs.createReadStream(localFilePath), + blockBlobURL, + 4 * 1024 * 1024, + 20, + { + progress: ev => console.log(ev) + } + ); + console.log("uploadStreamToBlockBlob success"); + + // Parallel uploading a browser File/Blob/ArrayBuffer in browsers with uploadBrowserDataToBlockBlob + // Uncomment following code in browsers because uploadBrowserDataToBlockBlob is only available in browsers + /* + const browserFile = document.getElementById("fileinput").files[0]; + await uploadBrowserDataToBlockBlob(Aborter.none, browserFile, blockBlobURL, { + blockSize: 4 * 1024 * 1024, // 4MB block size + parallelism: 20, // 20 concurrency + progress: ev => console.log(ev) + }); + */ + + // Parallel downloading a block blob into Node.js buffer + // downloadBlobToBuffer is only available in Node.js + const fileSize = fs.statSync(localFilePath).size; + const buffer = Buffer.alloc(fileSize); + await downloadBlobToBuffer( + Aborter.timeout(30 * 60 * 60 * 1000), + buffer, + blockBlobURL, + 0, + undefined, + { + blockSize: 4 * 1024 * 1024, // 4MB block size + parallelism: 20, // 20 concurrency + progress: ev => console.log(ev) + } + ); + console.log("downloadBlobToBuffer success"); + + // Delete container + await containerURL.delete(Aborter.none); + console.log("deleted container"); +} + +// An async method returns a Promise object, which is compatible with then().catch() coding style. +main() + .then(() => { + console.log("Successfully executed sample."); + }) + .catch(err => { + console.log(err.message); + }); diff --git a/file/swagger/README.md b/file/swagger/README.md new file mode 100644 index 0000000..63d6057 --- /dev/null +++ b/file/swagger/README.md @@ -0,0 +1,16 @@ +# Azure Storage TypeScript Protocol Layer + +> see https://aka.ms/autorest + +```yaml +package-name: azure-storage-file +title: StorageClient +description: Storage Client +enable-xml: true +generate-metadata: false +license-header: MICROSOFT_MIT_NO_VERSION +output-folder: ../lib/generated +input-file: ./file-storage-2018-03-28.json +model-date-time-as-string: true +optional-response-headers: true +``` diff --git a/file/swagger/file-storage-2018-03-28.json b/file/swagger/file-storage-2018-03-28.json new file mode 100644 index 0000000..2f125bc --- /dev/null +++ b/file/swagger/file-storage-2018-03-28.json @@ -0,0 +1,3106 @@ +{ + "swagger": "2.0", + "info": { + "title": "Azure File Storage", + "version": "2018-03-28", + "x-ms-code-generation-settings": { + "header": "MIT", + "strictSpecAdherence": false + } + }, + "x-ms-parameterized-host": { + "hostTemplate": "{url}", + "useSchemePrefix": false, + "positionInOperation": "first", + "parameters": [{ + "$ref": "#/parameters/Url" + }] + }, + "securityDefinitions": { + "File_shared_key": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + }, + "schemes": [ + "https" + ], + "consumes": [ + "application/xml", + "application/octet-stream", + "text/plain" + ], + "produces": [ + "application/xml", + "application/octet-stream", + "text/plain" + ], + "paths": { + + }, + "x-ms-paths": { + "/?restype=service&comp=properties": { + "put": { + "tags": [ + "service" + ], + "operationId": "Service_SetProperties", + "description": "Sets properties for a storage account's File service endpoint, including properties for Storage Analytics metrics and CORS (Cross-Origin Resource Sharing) rules.", + "parameters": [{ + "$ref": "#/parameters/StorageServiceProperties" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "202": { + "description": "Success (Accepted)", + "headers": { + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "get": { + "tags": [ + "service" + ], + "operationId": "Service_GetProperties", + "description": "Gets the properties of a storage account's File service, including properties for Storage Analytics metrics and CORS (Cross-Origin Resource Sharing) rules.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + } + }, + "schema": { + "$ref": "#/definitions/StorageServiceProperties" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "service" + ] + }, + { + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "properties" + ] + } + ] + }, + "/?comp=list": { + "get": { + "tags": [ + "service" + ], + "operationId": "Service_ListSharesSegment", + "description": "The List Shares Segment operation returns a list of the shares and share snapshots under the specified account.", + "parameters": [{ + "$ref": "#/parameters/Prefix" + }, + { + "$ref": "#/parameters/Marker" + }, + { + "$ref": "#/parameters/MaxResults" + }, + { + "$ref": "#/parameters/ListSharesInclude" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + } + }, + "schema": { + "$ref": "#/definitions/ListSharesResponse" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "NextMarker" + } + }, + "parameters": [{ + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "list" + ] + }] + }, + "/{shareName}?restype=share": { + "put": { + "tags": [ + "share" + ], + "operationId": "Share_Create", + "description": "Creates a new share under the specified account. If the share with the same name already exists, the operation fails.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/ShareQuota" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "201": { + "description": "Success, Share created.", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value which represents the version of the share, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. Any operation that modifies the share or its properties or metadata updates the last modified time. Operations on files do not affect the last modified time of the share." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "get": { + "tags": [ + "share" + ], + "operationId": "Share_GetProperties", + "description": "Returns all user-defined metadata and system properties for the specified share or share snapshot. The data returned does not include the share's list of files.", + "parameters": [{ + "$ref": "#/parameters/ShareSnapshot" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "x-ms-meta": { + "type": "string", + "description": "A set of name-value pairs that contain the user-defined metadata of the share.", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. Any operation that modifies the share or its properties updates the last modified time. Operations on files do not affect the last modified time of the share." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-share-quota": { + "x-ms-client-name": "Quota", + "type": "integer", + "description": "Returns the current share quota in GB." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "delete": { + "tags": [ + "share" + ], + "operationId": "Share_Delete", + "description": "Operation marks the specified share or share snapshot for deletion. The share or share snapshot and any files contained within it are later deleted during garbage collection.", + "parameters": [{ + "$ref": "#/parameters/ShareSnapshot" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/DeleteSnapshots" + } + ], + "responses": { + "202": { + "description": "Accepted", + "headers": { + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "share" + ] + }] + }, + "/{shareName}?restype=share&comp=snapshot": { + "put": { + "tags": [ + "share" + ], + "operationId": "Share_CreateSnapshot", + "description": "Creates a read-only snapshot of a share.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "201": { + "description": "Success, Share snapshot created.", + "headers": { + "x-ms-snapshot": { + "x-ms-client-name": "Snapshot", + "type": "string", + "description": "This header is a DateTime value that uniquely identifies the share snapshot. The value of this header may be used in subsequent requests to access the share snapshot. This value is opaque." + }, + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value which represents the version of the share snapshot, in quotes. A share snapshot cannot be modified, so the ETag of a given share snapshot never changes. However, if new metadata was supplied with the Snapshot Share request then the ETag of the share snapshot differs from that of the base share. If no metadata was specified with the request, the ETag of the share snapshot is identical to that of the base share at the time the share snapshot was taken." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. A share snapshot cannot be modified, so the last modified time of a given share snapshot never changes. However, if new metadata was supplied with the Snapshot Share request then the last modified time of the share snapshot differs from that of the base share. If no metadata was specified with the request, the last modified time of the share snapshot is identical to that of the base share at the time the share snapshot was taken." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "share" + ] + }, + { + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "snapshot" + ] + } + ] + }, + "/{shareName}?restype=share&comp=properties": { + "put": { + "tags": [ + "share" + ], + "operationId": "Share_SetQuota", + "description": "Sets quota for the specified share.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/ShareQuota" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. Any operation that modifies the share or its properties updates the last modified time. Operations on files do not affect the last modified time of the share." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "share" + ] + }, + { + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "properties" + ] + } + ] + }, + "/{shareName}?restype=share&comp=metadata": { + "put": { + "tags": [ + "share" + ], + "operationId": "Share_SetMetadata", + "description": "Sets one or more user-defined name-value pairs for the specified share.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. Any operation that modifies the share or its properties updates the last modified time. Operations on files do not affect the last modified time of the share." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "share" + ] + }, + { + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "metadata" + ] + } + ] + }, + "/{shareName}?restype=share&comp=acl": { + "get": { + "tags": [ + "share" + ], + "operationId": "Share_GetAccessPolicy", + "description": "Returns information about stored access policies specified on the share.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. Any operation that modifies the share or its properties updates the last modified time. Operations on files do not affect the last modified time of the share." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + }, + "schema": { + "$ref": "#/definitions/SignedIdentifiers" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "put": { + "tags": [ + "share" + ], + "operationId": "Share_SetAccessPolicy", + "description": "Sets a stored access policy for use with shared access signatures.", + "parameters": [{ + "$ref": "#/parameters/ShareAcl" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. Any operation that modifies the share or its properties updates the last modified time. Operations on files do not affect the last modified time of the share." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "share" + ] + }, + { + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "acl" + ] + } + ] + }, + "/{shareName}?restype=share&comp=stats": { + "get": { + "tags": [ + "share" + ], + "operationId": "Share_GetStatistics", + "description": "Retrieves statistics related to the share.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. Any operation that modifies the share or its properties updates the last modified time. Operations on files do not affect the last modified time of the share." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + }, + "schema": { + "$ref": "#/definitions/ShareStats" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "share" + ] + }, + { + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "stats" + ] + } + ] + }, + "/{shareName}/{directory}?restype=directory": { + "put": { + "tags": [ + "directory" + ], + "operationId": "Directory_Create", + "description": "Creates a new directory under the specified share or parent directory.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "201": { + "description": "Success, Directory created.", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value which represents the version of the directory, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. Any operation that modifies the directory or its properties updates the last modified time. Operations on files do not affect the last modified time of the directory." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "get": { + "tags": [ + "directory" + ], + "operationId": "Directory_GetProperties", + "description": "Returns all system properties for the specified directory, and can also be used to check the existence of a directory. The data returned does not include the files in the directory or any subdirectories.", + "parameters": [{ + "$ref": "#/parameters/ShareSnapshot" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "x-ms-meta": { + "type": "string", + "description": "A set of name-value pairs that contain metadata for the directory.", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the Directory was last modified. Operations on files within the directory do not affect the last modified time of the directory." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the directory metadata is completely encrypted using the specified algorithm. Otherwise, the value is set to false." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "delete": { + "tags": [ + "directory" + ], + "operationId": "Directory_Delete", + "description": "Removes the specified empty directory. Note that the directory must be empty before it can be deleted.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "202": { + "description": "Success (Accepted).", + "headers": { + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "directory" + ] + }] + }, + "/{shareName}/{directory}?restype=directory&comp=metadata": { + "put": { + "tags": [ + "directory" + ], + "operationId": "Directory_SetMetadata", + "description": "Updates user defined metadata for the specified directory.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "202": { + "description": "Success (Accepted).", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value which represents the version of the directory, in quotes." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "directory" + ] + }, + { + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "metadata" + ] + } + ] + }, + "/{shareName}/{directory}?restype=directory&comp=list": { + "get": { + "tags": [ + "directory" + ], + "operationId": "Directory_ListFilesAndDirectoriesSegment", + "description": "Returns a list of files or directories under the specified share or directory. It lists the contents only for a single level of the directory hierarchy.", + "parameters": [{ + + "$ref": "#/parameters/Prefix" + }, + { + "$ref": "#/parameters/ShareSnapshot" + }, + { + "$ref": "#/parameters/Marker" + }, + { + "$ref": "#/parameters/MaxResults" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "Content-Type": { + "type": "string", + "description": "Specifies the format in which the results are returned. Currently this value is 'application/xml'." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + }, + "schema": { + "$ref": "#/definitions/ListFilesAndDirectoriesSegmentResponse" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "NextMarker" + } + }, + "parameters": [{ + "name": "restype", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "directory" + ] + }, + { + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "list" + ] + } + ] + }, + "/{shareName}/{directory}/{fileName}": { + "put": { + "tags": [ + "file" + ], + "operationId": "File_Create", + "description": "Creates a new file or replaces a file. Note it only initializes the file with no content.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "name": "x-ms-content-length", + "x-ms-client-name": "fileContentLength", + "in": "header", + "description": "Specifies the maximum size for the file, up to 1 TB.", + "required": true, + "type": "integer", + "format": "int64" + }, + { + "$ref": "#/parameters/FileType" + }, + { + "$ref": "#/parameters/FileContentType" + }, + { + "$ref": "#/parameters/FileContentEncoding" + }, + { + "$ref": "#/parameters/FileContentLanguage" + }, + { + "$ref": "#/parameters/FileCacheControl" + }, + { + "$ref": "#/parameters/FileContentMD5" + }, + { + "$ref": "#/parameters/FileContentDisposition" + }, + { + "$ref": "#/parameters/Metadata" + } + ], + "responses": { + "201": { + "description": "Success, File created.", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value which represents the version of the file, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the share was last modified. Any operation that modifies the directory or its properties updates the last modified time. Operations on files do not affect the last modified time of the directory." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "get": { + "tags": [ + "file" + ], + "operationId": "File_Download", + "description": "Reads or downloads a file from the system, including its metadata and properties.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/Range" + }, + { + "$ref": "#/parameters/GetRangeContentMD5" + } + ], + "responses": { + "200": { + "description": "Succeeded to read the entire file.", + "headers": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the file was last modified. Any operation that modifies the file or its properties updates the last modified time." + }, + "x-ms-meta": { + "type": "string", + "description": "A set of name-value pairs associated with this file as user-defined metadata.", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The number of bytes present in the response body." + }, + "Content-Type": { + "type": "string", + "description": "The content type specified for the file. The default content type is 'application/octet-stream'" + }, + "Content-Range": { + "type": "string", + "description": "Indicates the range of bytes returned if the client requested a subset of the file by setting the Range request header." + }, + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "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." + }, + "Content-Encoding": { + "type": "string", + "description": "Returns the value that was specified for the Content-Encoding request header." + }, + "Cache-Control": { + "type": "string", + "description": "Returned if it was previously specified for the file." + }, + "Content-Disposition": { + "type": "string", + "description": "Returns the value that was specified for the 'x-ms-content-disposition' header and specifies how to process the response." + }, + "Content-Language": { + "type": "string", + "description": "Returns the value that was specified for the Content-Language request header." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Accept-Ranges": { + "type": "string", + "description": "Indicates that the service supports requests for partial file content." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-copy-completion-time": { + "x-ms-client-name": "CopyCompletionTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "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." + }, + "x-ms-copy-status-description": { + "x-ms-client-name": "CopyStatusDescription", + "type": "string", + "description": "Only appears when x-ms-copy-status is failed or pending. Describes cause of fatal or non-fatal copy operation failure." + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for the last attempted Copy File operation where this file was the destination file." + }, + "x-ms-copy-progress": { + "x-ms-client-name": "CopyProgress", + "type": "string", + "description": "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." + }, + "x-ms-copy-source": { + "x-ms-client-name": "CopySource", + "type": "string", + "description": "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." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by 'x-ms-copy-id'.", + "type": "string", + "enum": [ + "pending", + "success", + "aborted", + "failed" + ], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + }, + "x-ms-content-md5": { + "x-ms-client-name": "FileContentMD5", + "type": "string", + "format": "byte", + "description": "If the file 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 file'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." + }, + "x-ms-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "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)." + } + }, + "schema": { + "type": "object", + "format": "file" + } + }, + "206": { + "description": "Succeeded to read a specified range of the file.", + "headers": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the file was last modified. Any operation that modifies the file or its properties updates the last modified time." + }, + "x-ms-meta": { + "type": "string", + "description": "A set of name-value pairs associated with this file as user-defined metadata.", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The number of bytes present in the response body." + }, + "Content-Type": { + "type": "string", + "description": "The content type specified for the file. The default content type is 'application/octet-stream'" + }, + "Content-Range": { + "type": "string", + "description": "Indicates the range of bytes returned if the client requested a subset of the file by setting the Range request header." + }, + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "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." + }, + "Content-Encoding": { + "type": "string", + "description": "Returns the value that was specified for the Content-Encoding request header." + }, + "Cache-Control": { + "type": "string", + "description": "Returned if it was previously specified for the file." + }, + "Content-Disposition": { + "type": "string", + "description": "Returns the value that was specified for the 'x-ms-content-disposition' header and specifies how to process the response." + }, + "Content-Language": { + "type": "string", + "description": "Returns the value that was specified for the Content-Language request header." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Accept-Ranges": { + "type": "string", + "description": "Indicates that the service supports requests for partial file content." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-copy-completion-time": { + "x-ms-client-name": "CopyCompletionTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "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." + }, + "x-ms-copy-status-description": { + "x-ms-client-name": "CopyStatusDescription", + "type": "string", + "description": "Only appears when x-ms-copy-status is failed or pending. Describes cause of fatal or non-fatal copy operation failure." + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for the last attempted Copy File operation where this file was the destination file." + }, + "x-ms-copy-progress": { + "x-ms-client-name": "CopyProgress", + "type": "string", + "description": "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." + }, + "x-ms-copy-source": { + "x-ms-client-name": "CopySource", + "type": "string", + "description": "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." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by 'x-ms-copy-id'.", + "type": "string", + "enum": [ + "pending", + "success", + "aborted", + "failed" + ], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + }, + "x-ms-content-md5": { + "x-ms-client-name": "FileContentMD5", + "type": "string", + "format": "byte", + "description": "If the file 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 file'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." + }, + "x-ms-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "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)." + } + }, + "schema": { + "type": "object", + "format": "file" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "head": { + "tags": [ + "file" + ], + "operationId": "File_GetProperties", + "description": "Returns all user-defined metadata, standard HTTP properties, and system properties for the file. It does not return the content of the file.", + "parameters": [{ + "$ref": "#/parameters/ShareSnapshot" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the file was last modified. The date format follows RFC 1123. Any operation that modifies the file or its properties updates the last modified time." + }, + "x-ms-meta": { + "type": "string", + "description": "A set of name-value pairs associated with this file as user-defined metadata.", + "x-ms-client-name": "Metadata", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "x-ms-type": { + "x-ms-client-name": "FileType", + "description": "Returns the type File. Reserved for future use.", + "type": "string", + "enum": [ + "File" + ] + }, + "Content-Length": { + "type": "integer", + "format": "int64", + "description": "The size of the file in bytes. This header returns the value of the 'x-ms-content-length' header that is stored with the file." + }, + "Content-Type": { + "type": "string", + "description": "The content type specified for the file. The default content type is 'application/octet-stream'" + }, + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value that you can use to perform operations conditionally, in quotes." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "If the Content-MD5 header has been set for the file, the Content-MD5 response header is returned so that the client can check for message content integrity." + }, + "Content-Encoding": { + "type": "string", + "description": "If the Content-Encoding request header has previously been set for the file, the Content-Encoding value is returned in this header." + }, + "Cache-Control": { + "type": "string", + "description": "If the Cache-Control request header has previously been set for the file, the Cache-Control value is returned in this header." + }, + "Content-Disposition": { + "type": "string", + "description": "Returns the value that was specified for the 'x-ms-content-disposition' header and specifies how to process the response." + }, + "Content-Language": { + "type": "string", + "description": "Returns the value that was specified for the Content-Language request header." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-copy-completion-time": { + "x-ms-client-name": "CopyCompletionTime", + "type": "string", + "format": "date-time-rfc1123", + "description": "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." + }, + "x-ms-copy-status-description": { + "x-ms-client-name": "CopyStatusDescription", + "type": "string", + "description": "Only appears when x-ms-copy-status is failed or pending. Describes cause of fatal or non-fatal copy operation failure." + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for the last attempted Copy File operation where this file was the destination file." + }, + "x-ms-copy-progress": { + "x-ms-client-name": "CopyProgress", + "type": "string", + "description": "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." + }, + "x-ms-copy-source": { + "x-ms-client-name": "CopySource", + "type": "string", + "description": "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." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by 'x-ms-copy-id'.", + "type": "string", + "enum": [ + "pending", + "success", + "aborted", + "failed" + ], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + }, + "x-ms-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "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)." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "delete": { + "tags": [ + "file" + ], + "operationId": "File_Delete", + "description": "removes the file from the storage account.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "202": { + "description": "Success (Accepted).", + "headers": { + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + + ] + }, + "/{shareName}/{directory}/{fileName}?comp=properties": { + "put": { + "tags": [ + "file" + ], + "operationId": "File_SetHTTPHeaders", + "description": "Sets HTTP headers on the file.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "name": "x-ms-content-length", + "x-ms-client-name": "fileContentLength", + "in": "header", + "description": "Resizes a file to the specified size. If the specified byte value is less than the current size of the file, then all ranges above the specified byte value are cleared.", + "required": false, + "type": "integer", + "format": "int64" + }, + { + "$ref": "#/parameters/FileContentType" + }, + { + "$ref": "#/parameters/FileContentEncoding" + }, + { + "$ref": "#/parameters/FileContentLanguage" + }, + { + "$ref": "#/parameters/FileCacheControl" + }, + { + "$ref": "#/parameters/FileContentMD5" + }, + { + "$ref": "#/parameters/FileContentDisposition" + } + ], + "responses": { + "200": { + "description": "Success", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value which represents the version of the file, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the directory was last modified. Any operation that modifies the directory or its properties updates the last modified time. Operations on files do not affect the last modified time of the directory." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "properties" + ] + }] + }, + "/{shareName}/{directory}/{fileName}?comp=metadata": { + "put": { + "tags": [ + "file" + ], + "operationId": "File_SetMetadata", + "description": "Updates user-defined metadata for the specified file.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "202": { + "description": "Success (Accepted).", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value which represents the version of the file, in quotes." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "metadata" + ] + }] + }, + "/{shareName}/{directory}/{fileName}?comp=range": { + "put": { + "tags": [ + "file" + ], + "operationId": "File_UploadRange", + "description": "Upload a range of bytes to a file.", + "consumes": [ + "application/octet-stream" + ], + "parameters": [{ + "$ref": "#/parameters/OptionalBody" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "name": "x-ms-range", + "x-ms-client-name": "range", + "in": "header", + "description": "Specifies the range of bytes to be written. Both the start and end of the range must be specified. For an update operation, the range can be up to 4 MB in size. For a clear operation, the range can be up to the value of the file's full size. The File service accepts only a single byte range for the Range and 'x-ms-range' headers, and the byte range must be specified in the following format: bytes=startByte-endByte.", + "required": true, + "type": "string" + }, + { + "name": "x-ms-write", + "x-ms-client-name": "FileRangeWrite", + "in": "header", + "description": "Specify one of the following options: - Update: Writes the bytes specified by the request body into the specified range. The Range and Content-Length headers must match to perform the update. - Clear: Clears the specified range and releases the space used in storage for that range. To clear a range, set the Content-Length header to zero, and set the Range header to a value that indicates the range to clear, up to maximum file size.", + "required": true, + "type": "string", + "enum": [ + "update", + "clear" + ], + "default": "update", + "x-ms-enum": { + "name": "FileRangeWriteType", + "modelAsString": false + } + }, + { + "$ref": "#/parameters/ContentLength" + }, + { + "$ref": "#/parameters/ContentMD5" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "201": { + "description": "Success (Created).", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value which represents the version of the file, in quotes." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date and time the directory was last modified. Any operation that modifies the share or its properties or metadata updates the last modified time. Operations on files do not affect the last modified time of the share." + }, + "Content-MD5": { + "type": "string", + "format": "byte", + "description": "This header is returned so that the client can check for message content integrity. The value of this header is computed by the File service; it is not necessarily the same value as may have been specified in the request headers." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-request-server-encrypted": { + "x-ms-client-name": "IsServerEncrypted", + "type": "boolean", + "description": "The value of this header is set to true if the contents of the request are successfully encrypted using the specified algorithm, and false otherwise." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "range" + ] + }] + }, + "/{shareName}/{directory}/{fileName}?comp=rangelist": { + "get": { + "tags": [ + "file" + ], + "operationId": "File_GetRangeList", + "description": "Returns the list of valid ranges for a file.", + "parameters": [{ + "$ref": "#/parameters/ShareSnapshot" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "name": "x-ms-range", + "x-ms-client-name": "range", + "in": "header", + "description": "Specifies the range of bytes over which to list ranges, inclusively.", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success.", + "headers": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "The date/time that the file was last modified. Any operation that modifies the file, including an update of the file's metadata or properties, changes the file's last modified time." + }, + "ETag": { + "type": "string", + "format": "etag", + "description": "The ETag contains a value which represents the version of the file, in quotes." + }, + "x-ms-content-length": { + "x-ms-client-name": "FileContentLength", + "type": "integer", + "format": "int64", + "description": "The size of the file in bytes." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + }, + "schema": { + "$ref": "#/definitions/RangeList" + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "rangelist" + ] + }] + }, + "/{shareName}/{directory}/{fileName}?comp=copy": { + "put": { + "tags": [ + "file" + ], + "operationId": "File_StartCopy", + "description": "Copies a blob or file to a destination file within the storage account.", + "parameters": [{ + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + }, + { + "$ref": "#/parameters/Metadata" + }, + { + "$ref": "#/parameters/CopySource" + } + ], + "responses": { + "202": { + "description": "The copy file has been accepted with the specified copy status.", + "headers": { + "ETag": { + "type": "string", + "format": "etag", + "description": "If the copy is completed, contains the ETag of the destination file. If the copy is not complete, contains the ETag of the empty file created at the start of the copy." + }, + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123", + "description": "Returns the date/time that the copy operation to the destination file completed." + }, + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + }, + "x-ms-copy-id": { + "x-ms-client-name": "CopyId", + "type": "string", + "description": "String identifier for this copy operation. Use with Get File or Get File Properties to check the status of this copy operation, or pass to Abort Copy File to abort a pending copy." + }, + "x-ms-copy-status": { + "x-ms-client-name": "CopyStatus", + "description": "State of the copy operation identified by x-ms-copy-id.", + "type": "string", + "enum": [ + "pending", + "success", + "aborted", + "failed" + ], + "x-ms-enum": { + "name": "CopyStatusType", + "modelAsString": false + } + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [ + + ] + }, + "/{shareName}/{directory}/{fileName}?comp=copy©id={CopyId}": { + "put": { + "tags": [ + "file" + ], + "operationId": "File_AbortCopy", + "description": "Aborts a pending Copy File operation, and leaves a destination file with zero length and full metadata.", + "parameters": [{ + "$ref": "#/parameters/CopyId" + }, + { + "$ref": "#/parameters/Timeout" + }, + { + "$ref": "#/parameters/CopyActionAbort" + }, + { + "$ref": "#/parameters/ApiVersionParameter" + } + ], + "responses": { + "204": { + "description": "The delete request was accepted and the file will be deleted.", + "headers": { + "x-ms-request-id": { + "x-ms-client-name": "RequestId", + "type": "string", + "description": "This header uniquely identifies the request that was made and can be used for troubleshooting the request." + }, + "x-ms-version": { + "x-ms-client-name": "Version", + "type": "string", + "description": "Indicates the version of the File service used to execute the request." + }, + "Date": { + "type": "string", + "format": "date-time-rfc1123", + "description": "A UTC date/time value generated by the service that indicates the time at which the response was initiated." + } + } + }, + "default": { + "description": "Failure", + "headers": { + "x-ms-error-code": { + "x-ms-client-name": "ErrorCode", + "type": "string" + } + }, + "schema": { + "$ref": "#/definitions/StorageError" + } + } + } + }, + "parameters": [{ + "name": "comp", + "in": "query", + "required": true, + "type": "string", + "enum": [ + "copy" + ] + }] + } + }, + "definitions": { + "AccessPolicy": { + "description": "An Access policy.", + "type": "object", + "properties": { + "Start": { + "description": "The date-time the policy is active.", + "type": "string", + "format": "date-time" + }, + "Expiry": { + "description": "The date-time the policy expires.", + "type": "string", + "format": "date-time" + }, + "Permission": { + "description": "The permissions for the ACL policy.", + "type": "string" + } + } + }, + "CorsRule": { + "description": "CORS is an HTTP feature that enables a web application running under one domain to access resources in another domain. Web browsers implement a security restriction known as same-origin policy that prevents a web page from calling APIs in a different domain; CORS provides a secure way to allow one domain (the origin domain) to call APIs in another domain.", + "type": "object", + "required": [ + "AllowedOrigins", + "AllowedMethods", + "AllowedHeaders", + "ExposedHeaders", + "MaxAgeInSeconds" + ], + "properties": { + "AllowedOrigins": { + "description": "The origin domains that are permitted to make a request against the storage service via CORS. The origin domain is the domain from which the request originates. Note that the origin must be an exact case-sensitive match with the origin that the user age sends to the service. You can also use the wildcard character '*' to allow all origin domains to make requests via CORS.", + "type": "string" + }, + "AllowedMethods": { + "description": "The methods (HTTP request verbs) that the origin domain may use for a CORS request. (comma separated)", + "type": "string" + }, + "AllowedHeaders": { + "description": "The request headers that the origin domain may specify on the CORS request.", + "type": "string" + }, + "ExposedHeaders": { + "description": "The response headers that may be sent in the response to the CORS request and exposed by the browser to the request issuer.", + "type": "string" + }, + "MaxAgeInSeconds": { + "description": "The maximum amount time that a browser should cache the preflight OPTIONS request.", + "type": "integer", + "minimum": 0 + } + } + }, + "Entry": { + "description": "Abstract for entries that can be listed from Directory.", + "type": "object", + "required": [ + "EntryType", + "Name" + ], + "discriminator": "EntryType", + "x-ms-discriminator-value": "Entry", + "properties": { + "EntryType": { + "type": "string" + }, + "Name": { + "description": "Name of the entry.", + "type": "string" + } + } + }, + "DirectoryItem": { + "xml": { + "name": "Directory" + }, + "x-ms-discriminator-value": "Directory", + "description": "A listed directory item.", + "allOf": [{ + "$ref": "#/definitions/Entry" + }] + }, + "FileItem": { + "xml": { + "name": "File" + }, + "x-ms-discriminator-value": "File", + "description": "A listed file item.", + "allOf": [{ + "$ref": "#/definitions/Entry" + }, + { + "type": "object", + "required": [ + "Properties" + ], + "properties": { + "Properties": { + "$ref": "#/definitions/FileProperty" + } + } + } + ] + }, + "FileProperty": { + "description": "File properties.", + "type": "object", + "required": [ + "Content-Length" + ], + "properties": { + "Content-Length": { + "description": "Content length of the file. This value may not be up-to-date since an SMB client may have modified the file locally. The value of Content-Length may not reflect that fact until the handle is closed or the op-lock is broken. To retrieve current property values, call Get File Properties.", + "type": "integer", + "format": "int64" + } + } + }, + "ListFilesAndDirectoriesSegmentResponse": { + "xml": { + "name": "EnumerationResults" + }, + "description": "An enumeration of directories and files.", + "type": "object", + "required": [ + "ServiceEndpoint", + "ShareName", + "DirectoryPath", + "Prefix", + "NextMarker" + ], + "properties": { + "ServiceEndpoint": { + "type": "string", + "xml": { + "attribute": true + } + }, + "ShareName": { + "type": "string", + "xml": { + "attribute": true + } + }, + "ShareSnapshot": { + "type": "string", + "xml": { + "attribute": true + } + }, + "DirectoryPath": { + "type": "string", + "xml": { + "attribute": true + } + }, + "Prefix": { + "type": "string" + }, + "Marker": { + "type": "string" + }, + "MaxResults": { + "type": "integer" + }, + "Entries": { + "xml": { + "wrapped": true + }, + "type": "array", + "items": { + "$ref": "#/definitions/Entry" + } + }, + "NextMarker": { + "type": "string" + } + } + }, + "ListSharesResponse": { + "xml": { + "name": "EnumerationResults" + }, + "description": "An enumeration of shares.", + "type": "object", + "required": [ + "ServiceEndpoint", + "NextMarker" + ], + "properties": { + "ServiceEndpoint": { + "type": "string", + "xml": { + "attribute": true + } + }, + "Prefix": { + "type": "string" + }, + "Marker": { + "type": "string" + }, + "MaxResults": { + "type": "integer" + }, + "ShareItems": { + "type": "array", + "items": { + "$ref": "#/definitions/ShareItem" + }, + "xml": { + "name": "Shares", + "wrapped": true + } + }, + "NextMarker": { + "type": "string" + } + } + }, + "Metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Metrics": { + "description": "Storage Analytics metrics for file service.", + "required": [ + "Version", + "Enabled" + ], + "properties": { + "Version": { + "description": "The version of Storage Analytics to configure.", + "type": "string" + }, + "Enabled": { + "description": "Indicates whether metrics are enabled for the File service.", + "type": "boolean" + }, + "IncludeAPIs": { + "description": "Indicates whether metrics should generate summary statistics for called API operations.", + "type": "boolean" + }, + "RetentionPolicy": { + "$ref": "#/definitions/RetentionPolicy" + } + } + }, + "Range": { + "description": "An Azure Storage file range.", + "type": "object", + "required": [ + "Start", + "End" + ], + "properties": { + "Start": { + "type": "integer", + "format": "int64", + "description": "Start of the range." + }, + "End": { + "type": "integer", + "format": "int64", + "description": "End of the range." + } + } + }, + "RangeList": { + "description": "A list of non-overlapping valid ranges, sorted by increasing address range.", + "type": "array", + "items": { + "$ref": "#/definitions/Range" + }, + "xml": { + "wrapped": true, + "name": "Ranges" + } + }, + "StorageError": { + "type": "object", + "properties": { + "Message": { + "type": "string" + } + } + }, + "RetentionPolicy": { + "description": "The retention policy.", + "type": "object", + "required": [ + "Enabled" + ], + "properties": { + "Enabled": { + "description": "Indicates whether a retention policy is enabled for the File service. If false, metrics data is retained, and the user is responsible for deleting it.", + "type": "boolean" + }, + "Days": { + "description": "Indicates the number of days that metrics data should be retained. All data older than this value will be deleted. Metrics data is deleted on a best-effort basis after the retention period expires.", + "type": "integer", + "minimum": 1, + "maximum": 365 + } + } + }, + "ShareItem": { + "xml": { + "name": "Share" + }, + "description": "A listed Azure Storage share item.", + "type": "object", + "required": [ + "Name", + "Properties" + ], + "properties": { + "Name": { + "type": "string" + }, + "Snapshot": { + "type": "string" + }, + "Properties": { + "$ref": "#/definitions/ShareProperties" + }, + "Metadata": { + "$ref": "#/definitions/Metadata" + } + } + }, + "ShareProperties": { + "description": "Properties of a share.", + "type": "object", + "required": [ + "Last-Modified", + "Etag", + "Quota" + ], + "properties": { + "Last-Modified": { + "type": "string", + "format": "date-time-rfc1123" + }, + "Etag": { + "type": "string", + "format": "etag" + }, + "Quota": { + "type": "integer" + } + } + }, + "ShareStats": { + "description": "Stats for the share.", + "type": "object", + "required": [ + "ShareUsage" + ], + "properties": { + "ShareUsage": { + "description": "The approximate size of the data stored on the share, rounded up to the nearest gigabyte. Note that this value may not include all recently created or recently resized files.", + "type": "integer" + } + } + }, + "SignedIdentifier": { + "description": "Signed identifier.", + "type": "object", + "required": [ + "Id" + ], + "properties": { + "Id": { + "type": "string", + "description": "A unique id." + }, + "AccessPolicy": { + "description": "The access policy.", + "$ref": "#/definitions/AccessPolicy" + } + } + }, + "SignedIdentifiers": { + "description": "A collection of signed identifiers.", + "type": "array", + "items": { + "$ref": "#/definitions/SignedIdentifier" + }, + "xml": { + "wrapped": true, + "name": "SignedIdentifiers" + } + }, + "StorageServiceProperties": { + "description": "Storage service properties.", + "type": "object", + "properties": { + "HourMetrics": { + "description": "A summary of request statistics grouped by API in hourly aggregates for files.", + "$ref": "#/definitions/Metrics" + }, + "MinuteMetrics": { + "description": "A summary of request statistics grouped by API in minute aggregates for files.", + "$ref": "#/definitions/Metrics" + }, + "Cors": { + "description": "The set of CORS rules.", + "type": "array", + "items": { + "$ref": "#/definitions/CorsRule" + }, + "xml": { + "wrapped": true + } + } + } + } + }, + "parameters": { + "ApiVersionParameter": { + "name": "x-ms-version", + "x-ms-client-name": "version", + "in": "header", + "description": "Specifies the version of the operation to use for this request.", + "required": true, + "type": "string" + }, + "ContentLength": { + "name": "Content-Length", + "x-ms-client-name": "contentLength", + "in": "header", + "description": "Specifies the number of bytes being transmitted in the request body. When the x-ms-write header is set to clear, the value of this header must be set to zero.", + "required": true, + "type": "integer", + "format": "int64", + "x-ms-parameter-location": "method" + }, + "ContentMD5": { + "name": "Content-MD5", + "x-ms-client-name": "contentMD5", + "in": "header", + "description": "An MD5 hash of the content. This hash is used to verify the integrity of the data during transport. When the Content-MD5 header is specified, the File service compares the hash of the content that has arrived with the header value that was sent. If the two hashes do not match, the operation will fail with error code 400 (Bad Request).", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method" + }, + "CopyActionAbort": { + "name": "x-ms-copy-action", + "x-ms-client-name": "copyActionAbortConstant", + "in": "header", + "required": true, + "type": "string", + "enum": [ + "abort" + ], + "x-ms-parameter-location": "method" + }, + "CopyId": { + "name": "copyid", + "x-ms-client-name": "copyId", + "in": "query", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "The copy identifier provided in the x-ms-copy-id header of the original Copy File operation." + }, + "CopySource": { + "name": "x-ms-copy-source", + "x-ms-client-name": "copySource", + "in": "header", + "required": true, + "type": "string", + "x-ms-parameter-location": "method", + "description": "Specifies the URL of the source file or blob, up to 2 KB in length. To copy a file to another file within the same storage account, you may use Shared Key to authenticate the source file. If you are copying a file from another storage account, or if you are copying a blob from the same storage account or another storage account, then you must authenticate the source file or blob using a shared access signature. If the source is a public blob, no authentication is required to perform the copy operation. A file in a share snapshot can also be specified as a copy source." + }, + "DeleteSnapshots": { + "name": "x-ms-delete-snapshots", + "x-ms-client-name": "deleteSnapshots", + "description": "Specifies the option include to delete the base share and all of its snapshots.", + "in": "header", + "required": false, + "type": "string", + "enum": [ + "include" + ], + "x-ms-enum": { + "name": "DeleteSnapshotsOptionType", + "modelAsString": false + }, + "x-ms-parameter-location": "method" + }, + "FileCacheControl": { + "name": "x-ms-cache-control", + "x-ms-client-name": "fileCacheControl", + "description": "Sets the file's cache control. The File service stores this value but does not use or modify it.", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "FileContentDisposition": { + "name": "x-ms-content-disposition", + "x-ms-client-name": "fileContentDisposition", + "description": "Sets the file's Content-Disposition header.", + "in": "header", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "FileContentEncoding": { + "name": "x-ms-content-encoding", + "x-ms-client-name": "fileContentEncoding", + "in": "header", + "description": "Specifies which content encodings have been applied to the file.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "FileContentLanguage": { + "name": "x-ms-content-language", + "x-ms-client-name": "fileContentLanguage", + "in": "header", + "description": "Specifies the natural languages used by this resource.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "FileContentMD5": { + "name": "x-ms-content-md5", + "x-ms-client-name": "fileContentMD5", + "in": "header", + "description": "Sets the file's MD5 hash.", + "required": false, + "type": "string", + "format": "byte", + "x-ms-parameter-location": "method" + }, + "FileContentType": { + "name": "x-ms-content-type", + "x-ms-client-name": "fileContentType", + "in": "header", + "description": "Sets the MIME content type of the file. The default type is 'application/octet-stream'.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "FileType": { + "name": "x-ms-type", + "x-ms-client-name": "fileTypeConstant", + "in": "header", + "required": true, + "description": "Dummy constant parameter, file type can only be file.", + "type": "string", + "enum": [ + "file" + ], + "x-ms-parameter-location": "method" + }, + "GetRangeContentMD5": { + "name": "x-ms-range-get-content-md5", + "x-ms-client-name": "rangeGetContentMD5", + "in": "header", + "required": false, + "type": "boolean", + "x-ms-parameter-location": "method", + "description": "When this header is set to true and specified together with the Range header, the service returns the MD5 hash for the range, as long as the range is less than or equal to 4 MB in size." + }, + "ListSharesInclude": { + "name": "include", + "in": "query", + "description": "Include this parameter to specify one or more datasets to include in the response.", + "required": false, + "type": "array", + "collectionFormat": "csv", + "items": { + "type": "string", + "enum": [ + "snapshots", + "metadata" + ], + "x-ms-enum": { + "name": "ListSharesIncludeType", + "modelAsString": false + } + }, + "x-ms-parameter-location": "method" + }, + "Marker": { + "name": "marker", + "in": "query", + "description": "A string value that identifies the portion of the list to be returned with the next list operation. The operation returns a marker value within the response body if the list returned was not complete. The marker value may then be used in a subsequent call to request the next set of list items. The marker value is opaque to the client.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "MaxResults": { + "name": "maxresults", + "in": "query", + "description": "Specifies the maximum number of entries to return. If the request does not specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 items.", + "required": false, + "type": "integer", + "minimum": 1, + "x-ms-parameter-location": "method" + }, + "Metadata": { + "name": "x-ms-meta", + "x-ms-client-name": "metadata", + "in": "header", + "description": "A name-value pair to associate with a file storage object.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method", + "x-ms-header-collection-prefix": "x-ms-meta-" + }, + "OptionalBody": { + "name": "optionalbody", + "in": "body", + "description": "Initial data.", + "required": false, + "schema": { + "type": "object", + "format": "file" + }, + "x-ms-parameter-location": "method" + }, + "Prefix": { + "name": "prefix", + "in": "query", + "description": "Filters the results to return only entries whose name begins with the specified prefix.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "Range": { + "name": "x-ms-range", + "x-ms-client-name": "range", + "in": "header", + "description": "Return file data only from the specified byte range.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "Url": { + "name": "url", + "in": "path", + "description": "The URL of the service account, share, directory or file that is the target of the desired operation.", + "required": true, + "type": "string", + "x-ms-skip-url-encoding": true + }, + "ShareAcl": { + "name": "shareAcl", + "in": "body", + "description": "The ACL for the share.", + "schema": { + "$ref": "#/definitions/SignedIdentifiers" + }, + "x-ms-parameter-location": "method" + }, + "ShareQuota": { + "name": "x-ms-share-quota", + "x-ms-client-name": "quota", + "in": "header", + "description": "Specifies the maximum size of the share, in gigabytes.", + "required": false, + "type": "integer", + "minimum": 1, + "x-ms-parameter-location": "method" + }, + "ShareSnapshot": { + "name": "sharesnapshot", + "in": "query", + "description": "The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + }, + "StorageServiceProperties": { + "name": "StorageServiceProperties", + "in": "body", + "description": "The StorageService properties.", + "required": true, + "schema": { + "$ref": "#/definitions/StorageServiceProperties" + }, + "x-ms-parameter-location": "method" + }, + "Timeout": { + "name": "timeout", + "in": "query", + "description": "The timeout parameter is expressed in seconds. For more information, see Setting Timeouts for File Service Operations.", + "required": false, + "type": "integer", + "minimum": 0, + "x-ms-parameter-location": "method" + } + } +} \ No newline at end of file diff --git a/file/test/aborter.test.ts b/file/test/aborter.test.ts new file mode 100644 index 0000000..253507b --- /dev/null +++ b/file/test/aborter.test.ts @@ -0,0 +1,63 @@ +import * as assert from "assert"; + +import { Aborter } from "../lib/Aborter"; +import { ContainerURL } from "../lib/ContainerURL"; +import { getBSU, getUniqueName } from "./utils"; + +// tslint:disable:no-empty +describe("Aborter", () => { + const serviceURL = getBSU(); + let containerName: string = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + }); + + it("Should not abort after calling abort()", async () => { + await containerURL.create(Aborter.none); + }); + + it("Should abort when calling abort() before request finishes", async () => { + const aborter = Aborter.none; + const response = containerURL.create(aborter); + aborter.abort(); + try { + await response; + assert.fail(); + } catch (err) {} + }); + + it("Should not abort when calling abort() after request finishes", async () => { + const aborter = Aborter.none; + await containerURL.create(aborter); + aborter.abort(); + }); + + it("Should abort after aborter timeout", async () => { + try { + await containerURL.create(Aborter.timeout(1)); + assert.fail(); + } catch (err) {} + }); + + it("Should abort after father aborter calls abort()", async () => { + try { + const aborter = Aborter.none; + const response = containerURL.create(aborter.withTimeout(10 * 60 * 1000)); + aborter.abort(); + await response; + assert.fail(); + } catch (err) {} + }); + + it("Should abort after father aborter timeout", async () => { + try { + const aborter = Aborter.timeout(1); + const response = containerURL.create(aborter.withTimeout(10 * 60 * 1000)); + await response; + assert.fail(); + } catch (err) {} + }); +}); diff --git a/file/test/appendbloburl.test.ts b/file/test/appendbloburl.test.ts new file mode 100644 index 0000000..ee19bb3 --- /dev/null +++ b/file/test/appendbloburl.test.ts @@ -0,0 +1,82 @@ +import * as assert from "assert"; + +import { Aborter } from "../lib/Aborter"; +import { AppendBlobURL } from "../lib/AppendBlobURL"; +import { ContainerURL } from "../lib/ContainerURL"; +import { bodyToString, getBSU, getUniqueName } from "./utils"; + +describe("AppendBlobURL", () => { + const serviceURL = getBSU(); + let containerName: string = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + let blobName: string = getUniqueName("blob"); + let appendBlobURL = AppendBlobURL.fromContainerURL(containerURL, blobName); + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + blobName = getUniqueName("blob"); + appendBlobURL = AppendBlobURL.fromContainerURL(containerURL, blobName); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + it("create with default parameters", async () => { + await appendBlobURL.create(Aborter.none); + await appendBlobURL.download(Aborter.none, 0); + }); + + it("create with parameters configured", async () => { + const options = { + blobHTTPHeaders: { + blobCacheControl: "blobCacheControl", + blobContentDisposition: "blobContentDisposition", + blobContentEncoding: "blobContentEncoding", + blobContentLanguage: "blobContentLanguage", + blobContentType: "blobContentType" + }, + metadata: { + key1: "vala", + key2: "valb" + } + }; + await appendBlobURL.create(Aborter.none, options); + const properties = await appendBlobURL.getProperties(Aborter.none); + assert.equal( + properties.cacheControl, + options.blobHTTPHeaders.blobCacheControl + ); + assert.equal( + properties.contentDisposition, + options.blobHTTPHeaders.blobContentDisposition + ); + assert.equal( + properties.contentEncoding, + options.blobHTTPHeaders.blobContentEncoding + ); + assert.equal( + properties.contentLanguage, + options.blobHTTPHeaders.blobContentLanguage + ); + assert.equal( + properties.contentType, + options.blobHTTPHeaders.blobContentType + ); + assert.equal(properties.metadata!.key1, options.metadata.key1); + assert.equal(properties.metadata!.key2, options.metadata.key2); + }); + + it("appendBlock", async () => { + await appendBlobURL.create(Aborter.none); + + const content = "Hello World!"; + await appendBlobURL.appendBlock(Aborter.none, content, content.length); + + const downloadResponse = await appendBlobURL.download(Aborter.none, 0); + assert.equal(await bodyToString(downloadResponse, content.length), content); + assert.equal(downloadResponse.contentLength!, content.length); + }); +}); diff --git a/file/test/bloburl.test.ts b/file/test/bloburl.test.ts new file mode 100644 index 0000000..2f7e277 --- /dev/null +++ b/file/test/bloburl.test.ts @@ -0,0 +1,365 @@ +import * as assert from "assert"; + +import { isNode } from "ms-rest-js"; +import { Aborter } from "../lib/Aborter"; +import { BlobURL } from "../lib/BlobURL"; +import { BlockBlobURL } from "../lib/BlockBlobURL"; +import { ContainerURL } from "../lib/ContainerURL"; +import { + AccessTier, + BlobType, + LeaseDurationType, + LeaseStateType, + LeaseStatusType, + ListBlobsIncludeItem +} from "../lib/generated/models"; +import { bodyToString, getBSU, getUniqueName, sleep } from "./utils"; + +describe("BlobURL", () => { + const serviceURL = getBSU(); + let containerName: string = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + let blobName: string = getUniqueName("blob"); + let blobURL = BlobURL.fromContainerURL(containerURL, blobName); + let blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + const content = "Hello World"; + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + blobName = getUniqueName("blob"); + blobURL = BlobURL.fromContainerURL(containerURL, blobName); + blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + await blockBlobURL.upload(Aborter.none, content, content.length); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + it("download with with default parameters", async () => { + const result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual(await bodyToString(result, content.length), content); + }); + + it("download all parameters set", async () => { + const result = await blobURL.download(Aborter.none, 0, 1, { + rangeGetContentMD5: true + }); + assert.deepStrictEqual(await bodyToString(result, 1), content[0]); + }); + + it("setMetadata with new metadata set", async () => { + const metadata = { + a: "a", + b: "b" + }; + await blobURL.setMetadata(Aborter.none, { metadata }); + const result = await blobURL.getProperties(Aborter.none); + assert.deepStrictEqual(result.metadata, metadata); + }); + + it("setMetadata with cleaning up metadata", async () => { + const metadata = { + a: "a", + b: "b" + }; + await blobURL.setMetadata(Aborter.none, { metadata }); + const result = await blobURL.getProperties(Aborter.none); + assert.deepStrictEqual(result.metadata, metadata); + + await blobURL.setMetadata(Aborter.none); + const result2 = await blobURL.getProperties(Aborter.none); + assert.deepStrictEqual(result2.metadata, {}); + }); + + it("setHTTPHeaders with default parameters", async () => { + await blobURL.setHTTPHeaders(Aborter.none, {}); + const result = await blobURL.getProperties(Aborter.none); + + assert.deepStrictEqual(result.blobType, BlobType.BlockBlob); + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, {}); + assert.ok(!result.cacheControl); + assert.ok(!result.contentType); + assert.ok(!result.contentMD5); + assert.ok(!result.contentEncoding); + assert.ok(!result.contentLanguage); + assert.ok(!result.contentDisposition); + }); + + it("setHTTPHeaders with all parameters set", async () => { + const headers = { + blobCacheControl: "blobCacheControl", + blobContentDisposition: "blobContentDisposition", + blobContentEncoding: "blobContentEncoding", + blobContentLanguage: "blobContentLanguage", + blobContentMD5: isNode + ? Buffer.from([1, 2, 3, 4]) + : new Uint8Array([1, 2, 3, 4]), + blobContentType: "blobContentType" + }; + await blobURL.setHTTPHeaders(Aborter.none, { + blobHTTPHeaders: headers + }); + const result = await blobURL.getProperties(Aborter.none); + assert.deepStrictEqual(result.blobType, BlobType.BlockBlob); + assert.ok(result.lastModified); + assert.deepStrictEqual(result.metadata, {}); + assert.deepStrictEqual(result.cacheControl, headers.blobCacheControl); + assert.deepStrictEqual(result.contentType, headers.blobContentType); + assert.deepStrictEqual(result.contentMD5, headers.blobContentMD5); + assert.deepStrictEqual(result.contentEncoding, headers.blobContentEncoding); + assert.deepStrictEqual(result.contentLanguage, headers.blobContentLanguage); + assert.deepStrictEqual( + result.contentDisposition, + headers.blobContentDisposition + ); + }); + + it("acquireLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 30; + await blobURL.acquireLease(Aborter.none, guid, duration); + + const result = await blobURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + await blobURL.releaseLease(Aborter.none, guid); + }); + + it("releaseLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = -1; + await blobURL.acquireLease(Aborter.none, guid, duration); + + const result = await blobURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Infinite); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + await blobURL.releaseLease(Aborter.none, guid); + }); + + it("renewLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + await blobURL.acquireLease(Aborter.none, guid, duration); + + const result = await blobURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + await sleep(16 * 1000); + const result2 = await blobURL.getProperties(Aborter.none); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, LeaseStateType.Expired); + assert.equal(result2.leaseStatus, LeaseStatusType.Unlocked); + + await blobURL.renewLease(Aborter.none, guid); + const result3 = await blobURL.getProperties(Aborter.none); + assert.equal(result3.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result3.leaseState, LeaseStateType.Leased); + assert.equal(result3.leaseStatus, LeaseStatusType.Locked); + + await blobURL.releaseLease(Aborter.none, guid); + }); + + it("changeLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + await blobURL.acquireLease(Aborter.none, guid, duration); + + const result = await blobURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + const newGuid = "3c7e72ebb4304526bc53d8ecef03798f"; + await blobURL.changeLease(Aborter.none, guid, newGuid); + + await blobURL.getProperties(Aborter.none); + await blobURL.releaseLease(Aborter.none, newGuid); + }); + + it("breakLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + await blobURL.acquireLease(Aborter.none, guid, duration); + + const result = await blobURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + await blobURL.breakLease(Aborter.none, 3); + + const result2 = await blobURL.getProperties(Aborter.none); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, LeaseStateType.Breaking); + assert.equal(result2.leaseStatus, LeaseStatusType.Locked); + + await sleep(3 * 1000); + + const result3 = await blobURL.getProperties(Aborter.none); + assert.ok(!result3.leaseDuration); + assert.equal(result3.leaseState, LeaseStateType.Broken); + assert.equal(result3.leaseStatus, LeaseStatusType.Unlocked); + }); + + it("delete", async () => { + await blobURL.delete(Aborter.none); + }); + + // The following code illustrates deleting a snapshot after creating one + it("delete snapshot", async () => { + const result = await blobURL.createSnapshot(Aborter.none); + assert.ok(result.snapshot); + + const blobSnapshotURL = blobURL.withSnapshot(result.snapshot!); + await blobSnapshotURL.getProperties(Aborter.none); + + await blobSnapshotURL.delete(Aborter.none); + await blobURL.delete(Aborter.none); + + const result2 = await containerURL.listBlobFlatSegment( + Aborter.none, + undefined, + { + include: [ListBlobsIncludeItem.Snapshots] + } + ); + + // Verify that the snapshot is deleted + assert.equal(result2.segment.blobItems!.length, 0); + }); + + it("createSnapshot", async () => { + const result = await blobURL.createSnapshot(Aborter.none); + assert.ok(result.snapshot); + + const blobSnapshotURL = blobURL.withSnapshot(result.snapshot!); + await blobSnapshotURL.getProperties(Aborter.none); + + const result3 = await containerURL.listBlobFlatSegment( + Aborter.none, + undefined, + { + include: [ListBlobsIncludeItem.Snapshots] + } + ); + + // As a snapshot doesn't have leaseStatus and leaseState properties but origin blob has, + // let assign them to undefined both for other properties' easy comparison + // tslint:disable-next-line:max-line-length + result3.segment.blobItems![0].properties.leaseState = result3.segment.blobItems![1].properties.leaseState = undefined; + // tslint:disable-next-line:max-line-length + result3.segment.blobItems![0].properties.leaseStatus = result3.segment.blobItems![1].properties.leaseStatus = undefined; + // tslint:disable-next-line:max-line-length + result3.segment.blobItems![0].properties.accessTier = result3.segment.blobItems![1].properties.accessTier = undefined; + // tslint:disable-next-line:max-line-length + result3.segment.blobItems![0].properties.accessTierInferred = result3.segment.blobItems![1].properties.accessTierInferred = undefined; + + assert.deepStrictEqual( + result3.segment.blobItems![0].properties, + result3.segment.blobItems![1].properties + ); + assert.ok( + result3.segment.blobItems![0].snapshot || + result3.segment.blobItems![1].snapshot + ); + }); + + it("undelete", async () => { + const properties = await serviceURL.getProperties(Aborter.none); + if (!properties.deleteRetentionPolicy!.enabled) { + await serviceURL.setProperties(Aborter.none, { + deleteRetentionPolicy: { + days: 7, + enabled: true + } + }); + await sleep(15 * 1000); + } + + await blobURL.delete(Aborter.none); + + const result = await containerURL.listBlobFlatSegment( + Aborter.none, + undefined, + { + include: [ListBlobsIncludeItem.Deleted] + } + ); + assert.ok(result.segment.blobItems![0].deleted); + + await blobURL.undelete(Aborter.none); + const result2 = await containerURL.listBlobFlatSegment( + Aborter.none, + undefined, + { + include: [ListBlobsIncludeItem.Deleted] + } + ); + assert.ok(!result2.segment.blobItems![0].deleted); + }); + + it("startCopyFromURL", async () => { + const newBlobURL = BlobURL.fromContainerURL( + containerURL, + getUniqueName("copiedblob") + ); + const result = await newBlobURL.startCopyFromURL(Aborter.none, blobURL.url); + assert.ok(result.copyId); + + const properties1 = await blobURL.getProperties(Aborter.none); + const properties2 = await newBlobURL.getProperties(Aborter.none); + assert.deepStrictEqual(properties1.contentMD5, properties2.contentMD5); + assert.deepStrictEqual(properties2.copyId, result.copyId); + assert.deepStrictEqual(properties2.copySource, blobURL.url); + }); + + it("abortCopyFromURL should failed for a completed copy operation", async () => { + const newBlobURL = BlobURL.fromContainerURL( + containerURL, + getUniqueName("copiedblob") + ); + const result = await newBlobURL.startCopyFromURL(Aborter.none, blobURL.url); + assert.ok(result.copyId); + sleep(1 * 1000); + + try { + await newBlobURL.abortCopyFromURL(Aborter.none, result.copyId!); + assert.fail( + "AbortCopyFromURL should be failed and throw exception for an completed copy operation." + ); + } catch (err) { + assert.ok(true); + } + }); + + it("setTier set default to cool", async () => { + await blockBlobURL.setTier(Aborter.none, AccessTier.Cool); + const properties = await blockBlobURL.getProperties(Aborter.none); + assert.equal(properties.accessTier!.toLowerCase(), "cool"); + }); + + it("setTier set archive to hot", async () => { + await blockBlobURL.setTier(Aborter.none, AccessTier.Archive); + let properties = await blockBlobURL.getProperties(Aborter.none); + assert.equal(properties.accessTier!.toLowerCase(), "archive"); + + await blockBlobURL.setTier(Aborter.none, AccessTier.Hot); + properties = await blockBlobURL.getProperties(Aborter.none); + if (properties.archiveStatus) { + assert.equal( + properties.archiveStatus.toLowerCase(), + "rehydrate-pending-to-hot" + ); + } + }); +}); diff --git a/file/test/blockbloburl.test.ts b/file/test/blockbloburl.test.ts new file mode 100644 index 0000000..a207ac4 --- /dev/null +++ b/file/test/blockbloburl.test.ts @@ -0,0 +1,303 @@ +import * as assert from "assert"; + +import { Aborter } from "../lib/Aborter"; +import { BlobURL } from "../lib/BlobURL"; +import { BlockBlobURL } from "../lib/BlockBlobURL"; +import { ContainerURL } from "../lib/ContainerURL"; +import { BlockListType, PublicAccessType } from "../lib/generated/models"; +import { base64encode, bodyToString, getBSU, getUniqueName } from "./utils"; + +describe("BlockBlobURL", () => { + const serviceURL = getBSU(); + let containerName: string = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + let blobName: string = getUniqueName("blob"); + let blobURL = BlobURL.fromContainerURL(containerURL, blobName); + let blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + blobName = getUniqueName("blob"); + blobURL = BlobURL.fromContainerURL(containerURL, blobName); + blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + it("upload with string body and default parameters", async () => { + const body: string = getUniqueName("randomstring"); + await blockBlobURL.upload(Aborter.none, body, body.length); + const result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual(await bodyToString(result, body.length), body); + }); + + it("upload with string body and all parameters set", async () => { + const body: string = getUniqueName("randomstring"); + const options = { + blobCacheControl: "blobCacheControl", + blobContentDisposition: "blobContentDisposition", + blobContentEncoding: "blobContentEncoding", + blobContentLanguage: "blobContentLanguage", + blobContentType: "blobContentType", + metadata: { + keya: "vala", + keyb: "valb" + } + }; + await blockBlobURL.upload(Aborter.none, body, body.length, { + blobHTTPHeaders: options, + metadata: options.metadata + }); + const result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual(await bodyToString(result, body.length), body); + assert.deepStrictEqual(result.cacheControl, options.blobCacheControl); + assert.deepStrictEqual( + result.contentDisposition, + options.blobContentDisposition + ); + assert.deepStrictEqual(result.contentEncoding, options.blobContentEncoding); + assert.deepStrictEqual(result.contentLanguage, options.blobContentLanguage); + assert.deepStrictEqual(result.contentType, options.blobContentType); + assert.deepStrictEqual(result.metadata, options.metadata); + }); + + it("stageBlock", async () => { + const body = "HelloWorld"; + await blockBlobURL.stageBlock( + Aborter.none, + base64encode("1"), + body, + body.length + ); + await blockBlobURL.stageBlock( + Aborter.none, + base64encode("2"), + body, + body.length + ); + const listResponse = await blockBlobURL.getBlockList( + Aborter.none, + BlockListType.Uncommitted + ); + assert.equal(listResponse.uncommittedBlocks!.length, 2); + assert.equal(listResponse.uncommittedBlocks![0].name, base64encode("1")); + assert.equal(listResponse.uncommittedBlocks![0].size, body.length); + assert.equal(listResponse.uncommittedBlocks![1].name, base64encode("2")); + assert.equal(listResponse.uncommittedBlocks![1].size, body.length); + }); + + it("stageBlockFromURL copy source blob as single block", async () => { + const body = "HelloWorld"; + await blockBlobURL.upload(Aborter.none, body, body.length); + + // When testing is in Node.js environment with shared key, setAccessPolicy will work + // But in browsers testing with SAS tokens, below will throw an exception, ignore it + try { + await containerURL.setAccessPolicy( + Aborter.none, + PublicAccessType.Container + ); + // tslint:disable-next-line:no-empty + } catch (err) {} + + const newBlockBlobURL = BlockBlobURL.fromContainerURL( + containerURL, + getUniqueName("newblockblob") + ); + await newBlockBlobURL.stageBlockFromURL( + Aborter.none, + base64encode("1"), + blockBlobURL.url, + 0 + ); + + const listResponse = await newBlockBlobURL.getBlockList( + Aborter.none, + BlockListType.Uncommitted + ); + assert.equal(listResponse.uncommittedBlocks!.length, 1); + assert.equal(listResponse.uncommittedBlocks![0].name, base64encode("1")); + assert.equal(listResponse.uncommittedBlocks![0].size, body.length); + }); + + it("stageBlockFromURL copy source blob as separate blocks", async () => { + const body = "HelloWorld"; + await blockBlobURL.upload(Aborter.none, body, body.length); + + // When testing is in Node.js environment with shared key, setAccessPolicy will work + // But in browsers testing with SAS tokens, below will throw an exception, ignore it + try { + await containerURL.setAccessPolicy( + Aborter.none, + PublicAccessType.Container + ); + // tslint:disable-next-line:no-empty + } catch (err) {} + + const newBlockBlobURL = BlockBlobURL.fromContainerURL( + containerURL, + getUniqueName("newblockblob") + ); + await newBlockBlobURL.stageBlockFromURL( + Aborter.none, + base64encode("1"), + blockBlobURL.url, + 0, + 4 + ); + await newBlockBlobURL.stageBlockFromURL( + Aborter.none, + base64encode("2"), + blockBlobURL.url, + 4, + 4 + ); + await newBlockBlobURL.stageBlockFromURL( + Aborter.none, + base64encode("3"), + blockBlobURL.url, + 8, + 2 + ); + + const listResponse = await newBlockBlobURL.getBlockList( + Aborter.none, + BlockListType.Uncommitted + ); + assert.equal(listResponse.uncommittedBlocks!.length, 3); + assert.equal(listResponse.uncommittedBlocks![0].name, base64encode("1")); + assert.equal(listResponse.uncommittedBlocks![0].size, 4); + assert.equal(listResponse.uncommittedBlocks![1].name, base64encode("2")); + assert.equal(listResponse.uncommittedBlocks![1].size, 4); + assert.equal(listResponse.uncommittedBlocks![2].name, base64encode("3")); + assert.equal(listResponse.uncommittedBlocks![2].size, 2); + + await newBlockBlobURL.commitBlockList(Aborter.none, [ + base64encode("1"), + base64encode("2"), + base64encode("3") + ]); + + const downloadResponse = await newBlockBlobURL.download(Aborter.none, 0); + assert.equal(await bodyToString(downloadResponse, 10), body); + }); + + it("commitBlockList", async () => { + const body = "HelloWorld"; + await blockBlobURL.stageBlock( + Aborter.none, + base64encode("1"), + body, + body.length + ); + await blockBlobURL.stageBlock( + Aborter.none, + base64encode("2"), + body, + body.length + ); + await blockBlobURL.commitBlockList(Aborter.none, [ + base64encode("1"), + base64encode("2") + ]); + const listResponse = await blockBlobURL.getBlockList( + Aborter.none, + BlockListType.Committed + ); + assert.equal(listResponse.committedBlocks!.length, 2); + assert.equal(listResponse.committedBlocks![0].name, base64encode("1")); + assert.equal(listResponse.committedBlocks![0].size, body.length); + assert.equal(listResponse.committedBlocks![1].name, base64encode("2")); + assert.equal(listResponse.committedBlocks![1].size, body.length); + }); + + it("commitBlockList with all parameters set", async () => { + const body = "HelloWorld"; + await blockBlobURL.stageBlock( + Aborter.none, + base64encode("1"), + body, + body.length + ); + await blockBlobURL.stageBlock( + Aborter.none, + base64encode("2"), + body, + body.length + ); + + const options = { + blobCacheControl: "blobCacheControl", + blobContentDisposition: "blobContentDisposition", + blobContentEncoding: "blobContentEncoding", + blobContentLanguage: "blobContentLanguage", + blobContentType: "blobContentType", + metadata: { + keya: "vala", + keyb: "valb" + } + }; + await blockBlobURL.commitBlockList( + Aborter.none, + [base64encode("1"), base64encode("2")], + { + blobHTTPHeaders: options, + metadata: options.metadata + } + ); + + const listResponse = await blockBlobURL.getBlockList( + Aborter.none, + BlockListType.Committed + ); + assert.equal(listResponse.committedBlocks!.length, 2); + assert.equal(listResponse.committedBlocks![0].name, base64encode("1")); + assert.equal(listResponse.committedBlocks![0].size, body.length); + assert.equal(listResponse.committedBlocks![1].name, base64encode("2")); + assert.equal(listResponse.committedBlocks![1].size, body.length); + + const result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual( + await bodyToString(result, body.repeat(2).length), + body.repeat(2) + ); + assert.deepStrictEqual(result.cacheControl, options.blobCacheControl); + assert.deepStrictEqual( + result.contentDisposition, + options.blobContentDisposition + ); + assert.deepStrictEqual(result.contentEncoding, options.blobContentEncoding); + assert.deepStrictEqual(result.contentLanguage, options.blobContentLanguage); + assert.deepStrictEqual(result.contentType, options.blobContentType); + assert.deepStrictEqual(result.metadata, options.metadata); + }); + + it("getBlockList", async () => { + const body = "HelloWorld"; + await blockBlobURL.stageBlock( + Aborter.none, + base64encode("1"), + body, + body.length + ); + await blockBlobURL.stageBlock( + Aborter.none, + base64encode("2"), + body, + body.length + ); + await blockBlobURL.commitBlockList(Aborter.none, [base64encode("2")]); + const listResponse = await blockBlobURL.getBlockList( + Aborter.none, + BlockListType.All + ); + assert.equal(listResponse.committedBlocks!.length, 1); + assert.equal(listResponse.uncommittedBlocks!.length, 0); + assert.equal(listResponse.committedBlocks![0].name, base64encode("2")); + assert.equal(listResponse.committedBlocks![0].size, body.length); + }); +}); diff --git a/file/test/browser/highlevel.browser.test.ts b/file/test/browser/highlevel.browser.test.ts new file mode 100644 index 0000000..95dcd4f --- /dev/null +++ b/file/test/browser/highlevel.browser.test.ts @@ -0,0 +1,149 @@ +import * as assert from "assert"; + +import { Aborter } from "../../lib/Aborter"; +import { BlobURL } from "../../lib/BlobURL"; +import { BlockBlobURL } from "../../lib/BlockBlobURL"; +import { ContainerURL } from "../../lib/ContainerURL"; +import { uploadBrowserDataToBlockBlob } from "../../lib/highlevel.browser"; +import { + arrayBufferEqual, + blobToArrayBuffer, + blobToString, + bodyToString, + getBrowserFile, + getBSU, + getUniqueName, + isIE +} from "../utils/index.browser"; + +// tslint:disable:no-empty +describe("Highelvel", () => { + const serviceURL = getBSU(); + let containerName = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + let blobName = getUniqueName("blob"); + let blobURL = BlobURL.fromContainerURL(containerURL, blobName); + let blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + let tempFile1: File; + const tempFile1Length: number = 257 * 1024 * 1024 - 1; + let tempFile2: File; + const tempFile2Length: number = 1 * 1024 * 1024 - 1; + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + blobName = getUniqueName("blob"); + blobURL = BlobURL.fromContainerURL(containerURL, blobName); + blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + before(async () => { + tempFile1 = getBrowserFile(getUniqueName("browserfile"), tempFile1Length); + tempFile2 = getBrowserFile(getUniqueName("browserfile"), tempFile2Length); + }); + + after(async () => {}); + + it("uploadBrowserDataToBlockBlob should abort when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + const aborter = Aborter.timeout(1); + + try { + await uploadBrowserDataToBlockBlob(aborter, tempFile1, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 2 + }); + assert.fail(); + } catch (err) { + assert.ok((err.code as string).toLowerCase().includes("abort")); + } + }); + + it("uploadBrowserDataToBlockBlob should abort when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + const aborter = Aborter.timeout(1); + + try { + await uploadBrowserDataToBlockBlob(aborter, tempFile2, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 2 + }); + assert.fail(); + } catch (err) { + assert.ok((err.code as string).toLowerCase().includes("abort")); + } + }); + + it("uploadBrowserDataToBlockBlob should update progress when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + let eventTriggered = false; + const aborter = Aborter.none; + + try { + await uploadBrowserDataToBlockBlob(aborter, tempFile1, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 2, + progress: ev => { + assert.ok(ev.loadedBytes); + eventTriggered = true; + aborter.abort(); + } + }); + } catch (err) {} + assert.ok(eventTriggered); + }); + + it("uploadBrowserDataToBlockBlob should update progress when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + let eventTriggered = false; + const aborter = Aborter.none; + + try { + await uploadBrowserDataToBlockBlob(aborter, tempFile2, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 2, + progress: ev => { + assert.ok(ev.loadedBytes); + eventTriggered = true; + aborter.abort(); + } + }); + } catch (err) {} + assert.ok(eventTriggered); + }); + + it("uploadBrowserDataToBlockBlob should success when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + await uploadBrowserDataToBlockBlob(Aborter.none, tempFile2, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 2 + }); + + const downloadResponse = await blockBlobURL.download(Aborter.none, 0); + const downloadedString = await bodyToString(downloadResponse); + const uploadedString = await blobToString(tempFile2); + + assert.equal(uploadedString, downloadedString); + }); + + it("uploadBrowserDataToBlockBlob should success when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + if (isIE()) { + assert.ok( + true, + "Skip this case in IE11 which doesn't have enough memory for downloading validation" + ); + return; + } + + await uploadBrowserDataToBlockBlob(Aborter.none, tempFile1, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 2 + }); + + const downloadResponse = await blockBlobURL.download(Aborter.none, 0); + const buf1 = await blobToArrayBuffer(await downloadResponse.blobBody!); + const buf2 = await blobToArrayBuffer(tempFile1); + + assert.ok(arrayBufferEqual(buf1, buf2)); + }); +}); diff --git a/file/test/containerurl.test.ts b/file/test/containerurl.test.ts new file mode 100644 index 0000000..9dc2efc --- /dev/null +++ b/file/test/containerurl.test.ts @@ -0,0 +1,390 @@ +import * as assert from "assert"; + +import { Aborter } from "../lib/Aborter"; +import { BlobURL } from "../lib/BlobURL"; +import { BlockBlobURL } from "../lib/BlockBlobURL"; +import { ContainerURL } from "../lib/ContainerURL"; +import { + LeaseDurationType, + LeaseStateType, + LeaseStatusType, + ListBlobsIncludeItem, + PublicAccessType +} from "../lib/generated/models"; +import { getBSU, getUniqueName, sleep } from "./utils"; + +describe("ContainerURL", () => { + const serviceURL = getBSU(); + let containerName: string = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + it("setMetadata", async () => { + const metadata = { + key0: "val0", + keya: "vala", + keyb: "valb" + }; + await containerURL.setMetadata(Aborter.none, { + metadata + }); + + const result = await containerURL.getProperties(Aborter.none); + assert.deepEqual(result.metadata, metadata); + }); + + it("getProperties", async () => { + const result = await containerURL.getProperties(Aborter.none); + assert.ok(result.eTag!.length > 0); + assert.ok(result.lastModified); + assert.ok(!result.leaseDuration); + assert.equal(result.leaseState, LeaseStateType.Available); + assert.equal(result.leaseStatus, LeaseStatusType.Unlocked); + assert.ok(result.requestId); + assert.ok(result.version); + assert.ok(result.date); + assert.ok(!result.blobPublicAccess); + }); + + it("create with default parameters", done => { + // create() with default parameters has been tested in beforeEach + done(); + }); + + it("create with all parameters configured", async () => { + const cURL = ContainerURL.fromServiceURL( + serviceURL, + getUniqueName(containerName) + ); + const metadata = { key: "value" }; + const access = PublicAccessType.Container; + await cURL.create(Aborter.none, { metadata, access }); + const result = await cURL.getProperties(Aborter.none); + assert.deepEqual(result.blobPublicAccess, access); + assert.deepEqual(result.metadata, metadata); + }); + + it("delete", done => { + // delete() with default parameters has been tested in afterEach + done(); + }); + + it("acquireLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 30; + await containerURL.acquireLease(Aborter.none, guid, duration); + + const result = await containerURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + await containerURL.releaseLease(Aborter.none, guid); + }); + + it("releaseLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = -1; + await containerURL.acquireLease(Aborter.none, guid, duration); + + const result = await containerURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Infinite); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + await containerURL.releaseLease(Aborter.none, guid); + }); + + it("renewLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + await containerURL.acquireLease(Aborter.none, guid, duration); + + const result = await containerURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + await sleep(16 * 1000); + const result2 = await containerURL.getProperties(Aborter.none); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, LeaseStateType.Expired); + assert.equal(result2.leaseStatus, LeaseStatusType.Unlocked); + + await containerURL.renewLease(Aborter.none, guid); + const result3 = await containerURL.getProperties(Aborter.none); + assert.equal(result3.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result3.leaseState, LeaseStateType.Leased); + assert.equal(result3.leaseStatus, LeaseStatusType.Locked); + + await containerURL.releaseLease(Aborter.none, guid); + }); + + it("changeLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + await containerURL.acquireLease(Aborter.none, guid, duration); + + const result = await containerURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + const newGuid = "3c7e72ebb4304526bc53d8ecef03798f"; + await containerURL.changeLease(Aborter.none, guid, newGuid); + + await containerURL.getProperties(Aborter.none); + await containerURL.releaseLease(Aborter.none, newGuid); + }); + + it("breakLease", async () => { + const guid = "ca761232ed4211cebacd00aa0057b223"; + const duration = 15; + await containerURL.acquireLease(Aborter.none, guid, duration); + + const result = await containerURL.getProperties(Aborter.none); + assert.equal(result.leaseDuration, LeaseDurationType.Fixed); + assert.equal(result.leaseState, LeaseStateType.Leased); + assert.equal(result.leaseStatus, LeaseStatusType.Locked); + + await containerURL.breakLease(Aborter.none, 3); + + const result2 = await containerURL.getProperties(Aborter.none); + assert.ok(!result2.leaseDuration); + assert.equal(result2.leaseState, LeaseStateType.Breaking); + assert.equal(result2.leaseStatus, LeaseStatusType.Locked); + + await sleep(3 * 1000); + + const result3 = await containerURL.getProperties(Aborter.none); + assert.ok(!result3.leaseDuration); + assert.equal(result3.leaseState, LeaseStateType.Broken); + assert.equal(result3.leaseStatus, LeaseStatusType.Unlocked); + }); + + it("listBlobFlatSegment with default parameters", async () => { + const blobURLs = []; + for (let i = 0; i < 3; i++) { + const blobURL = BlobURL.fromContainerURL( + containerURL, + getUniqueName(`blockblob/${i}`) + ); + const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + await blockBlobURL.upload(Aborter.none, "", 0); + blobURLs.push(blobURL); + } + + const result = await containerURL.listBlobFlatSegment(Aborter.none); + assert.ok(result.serviceEndpoint.length > 0); + assert.ok(containerURL.url.indexOf(result.containerName)); + assert.deepStrictEqual(result.nextMarker, ""); + assert.deepStrictEqual(result.segment.blobItems!.length, blobURLs.length); + assert.ok(blobURLs[0].url.indexOf(result.segment.blobItems![0].name)); + + for (const blob of blobURLs) { + await blob.delete(Aborter.none); + } + }); + + it("listBlobFlatSegment with all parameters configured", async () => { + const blobURLs = []; + const prefix = "blockblob"; + const metadata = { + keya: "a", + keyb: "c" + }; + for (let i = 0; i < 2; i++) { + const blobURL = BlobURL.fromContainerURL( + containerURL, + getUniqueName(`${prefix}/${i}`) + ); + const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + await blockBlobURL.upload(Aborter.none, "", 0, { + metadata + }); + blobURLs.push(blobURL); + } + + const result = await containerURL.listBlobFlatSegment( + Aborter.none, + undefined, + { + include: [ + ListBlobsIncludeItem.Snapshots, + ListBlobsIncludeItem.Metadata, + ListBlobsIncludeItem.Uncommittedblobs, + ListBlobsIncludeItem.Copy, + ListBlobsIncludeItem.Deleted + ], + maxresults: 1, + prefix + } + ); + assert.ok(result.serviceEndpoint.length > 0); + assert.ok(containerURL.url.indexOf(result.containerName)); + assert.deepStrictEqual(result.segment.blobItems!.length, 1); + assert.ok(blobURLs[0].url.indexOf(result.segment.blobItems![0].name)); + assert.deepStrictEqual(result.segment.blobItems![0].metadata, metadata); + + const result2 = await containerURL.listBlobFlatSegment( + Aborter.none, + result.nextMarker, + { + include: [ + ListBlobsIncludeItem.Snapshots, + ListBlobsIncludeItem.Metadata, + ListBlobsIncludeItem.Uncommittedblobs, + ListBlobsIncludeItem.Copy, + ListBlobsIncludeItem.Deleted + ], + maxresults: 2, + prefix + } + ); + + assert.ok(result2.serviceEndpoint.length > 0); + assert.ok(containerURL.url.indexOf(result2.containerName)); + assert.deepStrictEqual(result2.segment.blobItems!.length, 1); + assert.ok(blobURLs[0].url.indexOf(result2.segment.blobItems![0].name)); + assert.deepStrictEqual(result2.segment.blobItems![0].metadata, metadata); + + for (const blob of blobURLs) { + await blob.delete(Aborter.none); + } + }); + + it("listBlobHierarchySegment with default parameters", async () => { + const blobURLs = []; + for (let i = 0; i < 3; i++) { + const blobURL = BlobURL.fromContainerURL( + containerURL, + getUniqueName(`blockblob${i}/${i}`) + ); + const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + await blockBlobURL.upload(Aborter.none, "", 0); + blobURLs.push(blobURL); + } + + const delimiter = "/"; + const result = await containerURL.listBlobHierarchySegment( + Aborter.none, + delimiter + ); + assert.ok(result.serviceEndpoint.length > 0); + assert.ok(containerURL.url.indexOf(result.containerName)); + assert.deepStrictEqual(result.nextMarker, ""); + assert.deepStrictEqual(result.delimiter, delimiter); + assert.deepStrictEqual( + result.segment.blobPrefixes!.length, + blobURLs.length + ); + + for (const blob of blobURLs) { + let i = 0; + assert.ok(blob.url.indexOf(result.segment.blobPrefixes![i++].name)); + } + + for (const blob of blobURLs) { + await blob.delete(Aborter.none); + } + }); + + it("listBlobHierarchySegment with all parameters configured", async () => { + const blobURLs = []; + const prefix = "blockblob"; + const metadata = { + keya: "a", + keyb: "c" + }; + const delimiter = "/"; + for (let i = 0; i < 2; i++) { + const blobURL = BlobURL.fromContainerURL( + containerURL, + getUniqueName(`${prefix}${i}${delimiter}${i}`) + ); + const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + await blockBlobURL.upload(Aborter.none, "", 0, { + metadata + }); + blobURLs.push(blobURL); + } + + const result = await containerURL.listBlobHierarchySegment( + Aborter.none, + delimiter, + undefined, + { + include: [ + ListBlobsIncludeItem.Metadata, + ListBlobsIncludeItem.Uncommittedblobs, + ListBlobsIncludeItem.Copy, + ListBlobsIncludeItem.Deleted + ], + maxresults: 1, + prefix + } + ); + assert.ok(result.serviceEndpoint.length > 0); + assert.ok(containerURL.url.indexOf(result.containerName)); + assert.deepStrictEqual(result.segment.blobPrefixes!.length, 1); + assert.deepStrictEqual(result.segment.blobItems!.length, 0); + assert.ok(blobURLs[0].url.indexOf(result.segment.blobPrefixes![0].name)); + + const result2 = await containerURL.listBlobHierarchySegment( + Aborter.none, + delimiter, + result.nextMarker, + { + include: [ + ListBlobsIncludeItem.Metadata, + ListBlobsIncludeItem.Uncommittedblobs, + ListBlobsIncludeItem.Copy, + ListBlobsIncludeItem.Deleted + ], + maxresults: 2, + prefix + } + ); + assert.ok(result2.serviceEndpoint.length > 0); + assert.ok(containerURL.url.indexOf(result2.containerName)); + assert.deepStrictEqual(result2.segment.blobPrefixes!.length, 1); + assert.deepStrictEqual(result2.segment.blobItems!.length, 0); + assert.ok(blobURLs[0].url.indexOf(result2.segment.blobPrefixes![0].name)); + + const result3 = await containerURL.listBlobHierarchySegment( + Aborter.none, + delimiter, + undefined, + { + include: [ + ListBlobsIncludeItem.Metadata, + ListBlobsIncludeItem.Uncommittedblobs, + ListBlobsIncludeItem.Copy, + ListBlobsIncludeItem.Deleted + ], + maxresults: 2, + prefix: `${prefix}0${delimiter}` + } + ); + assert.ok(result3.serviceEndpoint.length > 0); + assert.ok(containerURL.url.indexOf(result3.containerName)); + assert.deepStrictEqual(result3.nextMarker, ""); + assert.deepStrictEqual(result3.delimiter, delimiter); + assert.deepStrictEqual(result3.segment.blobItems!.length, 1); + assert.deepStrictEqual(result3.segment.blobItems![0].metadata, metadata); + assert.ok(blobURLs[0].url.indexOf(result3.segment.blobItems![0].name)); + + for (const blob of blobURLs) { + await blob.delete(Aborter.none); + } + }); +}); diff --git a/file/test/node/blockbloburl.test.ts b/file/test/node/blockbloburl.test.ts new file mode 100644 index 0000000..0167bb1 --- /dev/null +++ b/file/test/node/blockbloburl.test.ts @@ -0,0 +1,41 @@ +import * as assert from "assert"; + +import { Aborter } from "../../lib/Aborter"; +import { BlobURL } from "../../lib/BlobURL"; +import { BlockBlobURL } from "../../lib/BlockBlobURL"; +import { ContainerURL } from "../../lib/ContainerURL"; +import { getBSU, getUniqueName } from "../utils"; + +describe("BlockBlobURL Node.js only", () => { + const serviceURL = getBSU(); + let containerName: string = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + let blobName: string = getUniqueName("blob"); + let blobURL = BlobURL.fromContainerURL(containerURL, blobName); + let blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + blobName = getUniqueName("blob"); + blobURL = BlobURL.fromContainerURL(containerURL, blobName); + blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + it("upload with Readable stream body and default parameters", async () => { + const body: string = getUniqueName("randomstring"); + const bodyBuffer = Buffer.from(body); + + await blockBlobURL.upload(Aborter.none, bodyBuffer, body.length); + const result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual( + result.readableStreamBody!.read(body.length)!.toString(), + body + ); + }); +}); diff --git a/file/test/node/containerurl.test.ts b/file/test/node/containerurl.test.ts new file mode 100644 index 0000000..4665651 --- /dev/null +++ b/file/test/node/containerurl.test.ts @@ -0,0 +1,50 @@ +import * as assert from "assert"; + +import { Aborter } from "../../lib/Aborter"; +import { ContainerURL } from "../../lib/ContainerURL"; +import { PublicAccessType } from "../../lib/generated/models"; +import { getBSU, getUniqueName } from "../utils"; + +describe("ContainerURL", () => { + const serviceURL = getBSU(); + let containerName: string = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + it("getAccessPolicy", async () => { + const result = await containerURL.getAccessPolicy(Aborter.none); + assert.ok(result.eTag!.length > 0); + assert.ok(result.lastModified); + assert.ok(result.requestId); + assert.ok(result.version); + assert.ok(result.date); + }); + + it("setAccessPolicy", async () => { + const access = PublicAccessType.Blob; + const containerAcl = [ + { + accessPolicy: { + expiry: new Date("2018-12-31T11:22:33.4567890Z"), + permission: "rwd", + start: new Date("2017-12-31T11:22:33.4567890Z") + }, + id: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=" + } + ]; + + await containerURL.setAccessPolicy(Aborter.none, access, containerAcl); + const result = await containerURL.getAccessPolicy(Aborter.none); + assert.deepEqual(result.signedIdentifiers, containerAcl); + assert.deepEqual(result.blobPublicAccess, access); + }); +}); diff --git a/file/test/node/highlevel.node.test.ts b/file/test/node/highlevel.node.test.ts new file mode 100644 index 0000000..a7b0b14 --- /dev/null +++ b/file/test/node/highlevel.node.test.ts @@ -0,0 +1,316 @@ +import * as assert from "assert"; +import * as fs from "fs"; +import * as path from "path"; +import { Aborter } from "../../lib/Aborter"; +import { + downloadBlobToBuffer, + uploadFileToBlockBlob, + uploadStreamToBlockBlob +} from "../../lib/highlevel.node"; +import { + createRandomLocalFile, + getBSU, + getUniqueName, + readStreamToLocalFile +} from "../utils/index"; + +import { BlobURL, BlockBlobURL, ContainerURL } from "../../lib"; + +// tslint:disable:no-empty +describe("Highlevel", () => { + const serviceURL = getBSU(); + let containerName = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + let blobName = getUniqueName("blob"); + let blobURL = BlobURL.fromContainerURL(containerURL, blobName); + let blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + let tempFileSmall: string; + let tempFileSmallLength: number; + let tempFileLarge: string; + let tempFileLargeLength: number; + const tempFolderPath = "temp"; + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + blobName = getUniqueName("blob"); + blobURL = BlobURL.fromContainerURL(containerURL, blobName); + blockBlobURL = BlockBlobURL.fromBlobURL(blobURL); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + before(async () => { + if (!fs.existsSync(tempFolderPath)) { + fs.mkdirSync(tempFolderPath); + } + tempFileLarge = await createRandomLocalFile( + tempFolderPath, + 257, + 1024 * 1024 + ); + tempFileLargeLength = 257 * 1024 * 1024; + tempFileSmall = await createRandomLocalFile( + tempFolderPath, + 15, + 1024 * 1024 + ); + tempFileSmallLength = 15 * 1024 * 1024; + }); + + after(async () => { + fs.unlinkSync(tempFileLarge); + fs.unlinkSync(tempFileSmall); + }); + + it("uploadFileToBlockBlob should success when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + await uploadFileToBlockBlob(Aborter.none, tempFileLarge, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 20 + }); + + const downloadResponse = await blockBlobURL.download(Aborter.none, 0); + const downloadedFile = path.join( + tempFolderPath, + getUniqueName("downloadfile.") + ); + await readStreamToLocalFile( + downloadResponse.readableStreamBody!, + downloadedFile + ); + + const downloadedData = await fs.readFileSync(downloadedFile); + const uploadedData = await fs.readFileSync(tempFileLarge); + + fs.unlinkSync(downloadedFile); + assert.ok(downloadedData.equals(uploadedData)); + }); + + it("uploadFileToBlockBlob should success when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + await uploadFileToBlockBlob(Aborter.none, tempFileSmall, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 20 + }); + + const downloadResponse = await blockBlobURL.download(Aborter.none, 0); + const downloadedFile = path.join( + tempFolderPath, + getUniqueName("downloadfile.") + ); + await readStreamToLocalFile( + downloadResponse.readableStreamBody!, + downloadedFile + ); + + const downloadedData = await fs.readFileSync(downloadedFile); + const uploadedData = await fs.readFileSync(tempFileSmall); + + fs.unlinkSync(downloadedFile); + assert.ok(downloadedData.equals(uploadedData)); + }); + + it("uploadFileToBlockBlob should abort when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + const aborter = Aborter.timeout(1); + + try { + await uploadFileToBlockBlob(aborter, tempFileLarge, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 20 + }); + assert.fail(); + } catch (err) { + assert.ok((err.code as string).toLowerCase().includes("abort")); + } + }); + + it("uploadFileToBlockBlob should abort when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + const aborter = Aborter.timeout(1); + + try { + await uploadFileToBlockBlob(aborter, tempFileSmall, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 20 + }); + assert.fail(); + } catch (err) { + assert.ok((err.code as string).toLowerCase().includes("abort")); + } + }); + + it("uploadFileToBlockBlob should update progress when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + let eventTriggered = false; + const aborter = Aborter.none; + + try { + await uploadFileToBlockBlob(aborter, tempFileLarge, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 20, + progress: ev => { + assert.ok(ev.loadedBytes); + eventTriggered = true; + aborter.abort(); + } + }); + } catch (err) {} + assert.ok(eventTriggered); + }); + + it("uploadFileToBlockBlob should update progress when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES", async () => { + let eventTriggered = false; + const aborter = Aborter.none; + + try { + await uploadFileToBlockBlob(aborter, tempFileSmall, blockBlobURL, { + blockSize: 4 * 1024 * 1024, + parallelism: 20, + progress: ev => { + assert.ok(ev.loadedBytes); + eventTriggered = true; + aborter.abort(); + } + }); + } catch (err) {} + assert.ok(eventTriggered); + }); + + it("uploadStreamToBlockBlob should success", async () => { + const rs = fs.createReadStream(tempFileLarge); + await uploadStreamToBlockBlob( + Aborter.none, + rs, + blockBlobURL, + 4 * 1024 * 1024, + 20 + ); + + const downloadResponse = await blockBlobURL.download(Aborter.none, 0); + + const downloadFilePath = path.join("./", getUniqueName("downloadFile")); + await readStreamToLocalFile( + downloadResponse.readableStreamBody!, + downloadFilePath + ); + + const downloadedBuffer = fs.readFileSync(downloadFilePath); + const uploadedBuffer = fs.readFileSync(tempFileLarge); + assert.ok(uploadedBuffer.equals(downloadedBuffer)); + + fs.unlinkSync(downloadFilePath); + }); + + it("uploadStreamToBlockBlob should abort", async () => { + const rs = fs.createReadStream(tempFileLarge); + const aborter = Aborter.timeout(1); + + try { + await uploadStreamToBlockBlob( + aborter, + rs, + blockBlobURL, + 4 * 1024 * 1024, + 20 + ); + assert.fail(); + } catch (err) { + assert.ok((err.code as string).toLowerCase().includes("abort")); + } + }); + + it("uploadStreamToBlockBlob should update progress event", async () => { + const rs = fs.createReadStream(tempFileLarge); + let eventTriggered = false; + + await uploadStreamToBlockBlob( + Aborter.none, + rs, + blockBlobURL, + 4 * 1024 * 1024, + 20, + { + progress: ev => { + assert.ok(ev.loadedBytes); + eventTriggered = true; + } + } + ); + assert.ok(eventTriggered); + }); + + it("downloadBlobToBuffer should success", async () => { + const rs = fs.createReadStream(tempFileLarge); + await uploadStreamToBlockBlob( + Aborter.none, + rs, + blockBlobURL, + 4 * 1024 * 1024, + 20 + ); + + const buf = Buffer.alloc(tempFileLargeLength); + await downloadBlobToBuffer(Aborter.none, buf, blockBlobURL, 0, undefined, { + blockSize: 4 * 1024 * 1024, + parallelism: 20 + }); + + const localFileContent = fs.readFileSync(tempFileLarge); + assert.ok(localFileContent.equals(buf)); + }); + + it("downloadBlobToBuffer should abort", async () => { + const rs = fs.createReadStream(tempFileLarge); + await uploadStreamToBlockBlob( + Aborter.none, + rs, + blockBlobURL, + 4 * 1024 * 1024, + 20 + ); + + try { + const buf = Buffer.alloc(tempFileLargeLength); + await downloadBlobToBuffer( + Aborter.timeout(1), + buf, + blockBlobURL, + 0, + undefined, + { + blockSize: 4 * 1024 * 1024, + parallelism: 20 + } + ); + assert.fail(); + } catch (err) { + assert.ok((err.code as string).toLowerCase().includes("abort")); + } + }); + + it("downloadBlobToBuffer should update progress event", async () => { + const rs = fs.createReadStream(tempFileSmall); + await uploadStreamToBlockBlob( + Aborter.none, + rs, + blockBlobURL, + 4 * 1024 * 1024, + 10 + ); + + let eventTriggered = false; + const buf = Buffer.alloc(tempFileSmallLength); + const aborter = Aborter.none; + try { + await downloadBlobToBuffer(aborter, buf, blockBlobURL, 0, undefined, { + blockSize: 1 * 1024, + parallelism: 1, + progress: () => { + eventTriggered = true; + aborter.abort(); + } + }); + } catch (err) {} + assert.ok(eventTriggered); + }); +}); diff --git a/file/test/node/pagebloburl.test.ts b/file/test/node/pagebloburl.test.ts new file mode 100644 index 0000000..f3633c6 --- /dev/null +++ b/file/test/node/pagebloburl.test.ts @@ -0,0 +1,87 @@ +import * as assert from "assert"; + +import { Aborter } from "../../lib/Aborter"; +import { BlobURL } from "../../lib/BlobURL"; +import { ContainerURL } from "../../lib/ContainerURL"; +import { + ListBlobsIncludeItem, + PublicAccessType +} from "../../lib/generated/models"; +import { PageBlobURL } from "../../lib/PageBlobURL"; +import { getBSU, getUniqueName } from "../utils"; + +describe("PageBlobURL", () => { + const serviceURL = getBSU(); + let containerName: string = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + let blobName: string = getUniqueName("blob"); + let blobURL = BlobURL.fromContainerURL(containerURL, blobName); + let pageBlobURL = PageBlobURL.fromBlobURL(blobURL); + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + blobName = getUniqueName("blob"); + blobURL = BlobURL.fromContainerURL(containerURL, blobName); + pageBlobURL = PageBlobURL.fromBlobURL(blobURL); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + it("startCopyIncremental", async () => { + await pageBlobURL.create(Aborter.none, 1024, { + metadata: { + sourcemeta: "val" + } + }); + await pageBlobURL.uploadPages(Aborter.none, "b".repeat(1024), 0, 1024); + + let snapshotResult = await pageBlobURL.createSnapshot(Aborter.none); + assert.ok(snapshotResult.snapshot); + + const destPageBlobURL = PageBlobURL.fromContainerURL( + containerURL, + getUniqueName("page") + ); + + await containerURL.setAccessPolicy( + Aborter.none, + PublicAccessType.Container + ); + let copySource = pageBlobURL.withSnapshot(snapshotResult.snapshot!).url; + await destPageBlobURL.startCopyIncremental(Aborter.none, copySource); + let listBlobResponse = await containerURL.listBlobFlatSegment( + Aborter.none, + undefined, + { + include: [ListBlobsIncludeItem.Copy, ListBlobsIncludeItem.Snapshots] + } + ); + + assert.equal(listBlobResponse.segment.blobItems.length, 4); + + await pageBlobURL.uploadPages(Aborter.none, "c".repeat(1024), 0, 1024); + snapshotResult = await pageBlobURL.createSnapshot(Aborter.none); + assert.ok(snapshotResult.snapshot); + copySource = pageBlobURL.withSnapshot(snapshotResult.snapshot!).url; + await destPageBlobURL.startCopyIncremental(Aborter.none, copySource); + + listBlobResponse = await containerURL.listBlobFlatSegment( + Aborter.none, + undefined, + { + include: [ListBlobsIncludeItem.Copy, ListBlobsIncludeItem.Snapshots] + } + ); + + assert.equal(listBlobResponse.segment.blobItems.length, 6); + + const pageBlobProperties = await destPageBlobURL.getProperties( + Aborter.none + ); + assert.equal(pageBlobProperties.metadata!.sourcemeta, "val"); + }); +}); diff --git a/file/test/node/sharedkeycredentialpolicy.test.ts b/file/test/node/sharedkeycredentialpolicy.test.ts new file mode 100644 index 0000000..f93d5b4 --- /dev/null +++ b/file/test/node/sharedkeycredentialpolicy.test.ts @@ -0,0 +1,41 @@ +import { Aborter } from "../../lib/Aborter"; +import { BlockBlobURL } from "../../lib/BlockBlobURL"; +import { ContainerURL } from "../../lib/ContainerURL"; +import { getBSU, getUniqueName } from "../utils/index"; + +describe("SharedKeyCredentialPolicy Node.js only", () => { + const serviceURL = getBSU(); + const containerName: string = getUniqueName("1container-with-dash"); + const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + + before(async () => { + await containerURL.create(Aborter.none); + }); + + after(async () => { + await containerURL.delete(Aborter.none); + }); + + it("SharedKeyCredentialPolicy should work with special container and blob names with spaces", async () => { + const blobName: string = getUniqueName("blob empty"); + const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName); + + await blockBlobURL.upload(Aborter.none, "A", 1); + }); + + it("SharedKeyCredentialPolicy should work with special container and blob names with /", async () => { + const blobName: string = getUniqueName("////blob/empty /another"); + const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName); + + await blockBlobURL.upload(Aborter.none, "A", 1); + await blockBlobURL.getProperties(Aborter.none); + }); + + it("SharedKeyCredentialPolicy should work with special container and blob names uppercase", async () => { + const blobName: string = getUniqueName("////Upper/blob/empty /another"); + const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName); + + await blockBlobURL.upload(Aborter.none, "A", 1); + await blockBlobURL.getProperties(Aborter.none); + }); +}); diff --git a/file/test/pagebloburl.test.ts b/file/test/pagebloburl.test.ts new file mode 100644 index 0000000..878451e --- /dev/null +++ b/file/test/pagebloburl.test.ts @@ -0,0 +1,199 @@ +import * as assert from "assert"; +import { bodyToString, getBSU, getUniqueName } from "./utils"; + +import { Aborter } from "../lib/Aborter"; +import { BlobURL } from "../lib/BlobURL"; +import { ContainerURL } from "../lib/ContainerURL"; +import * as Models from "../lib/generated/models"; +import { PageBlobURL } from "../lib/PageBlobURL"; + +describe("PageBlobURL", () => { + const serviceURL = getBSU(); + let containerName: string = getUniqueName("container"); + let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + let blobName: string = getUniqueName("blob"); + let blobURL = BlobURL.fromContainerURL(containerURL, blobName); + let pageBlobURL = PageBlobURL.fromBlobURL(blobURL); + + beforeEach(async () => { + containerName = getUniqueName("container"); + containerURL = ContainerURL.fromServiceURL(serviceURL, containerName); + await containerURL.create(Aborter.none); + blobName = getUniqueName("blob"); + blobURL = BlobURL.fromContainerURL(containerURL, blobName); + pageBlobURL = PageBlobURL.fromBlobURL(blobURL); + }); + + afterEach(async () => { + await containerURL.delete(Aborter.none); + }); + + it("create with default parameters", async () => { + await pageBlobURL.create(Aborter.none, 512); + + const result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual( + await bodyToString(result, 512), + "\u0000".repeat(512) + ); + }); + + it("create with all parameters set", async () => { + const options = { + blobHTTPHeaders: { + blobCacheControl: "blobCacheControl", + blobContentDisposition: "blobContentDisposition", + blobContentEncoding: "blobContentEncoding", + blobContentLanguage: "blobContentLanguage", + blobContentType: "blobContentType" + }, + metadata: { + key1: "vala", + key2: "valb" + } + }; + await pageBlobURL.create(Aborter.none, 512, options); + + const result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual( + await bodyToString(result, 512), + "\u0000".repeat(512) + ); + + const properties = await blobURL.getProperties(Aborter.none); + assert.equal( + properties.cacheControl, + options.blobHTTPHeaders.blobCacheControl + ); + assert.equal( + properties.contentDisposition, + options.blobHTTPHeaders.blobContentDisposition + ); + assert.equal( + properties.contentEncoding, + options.blobHTTPHeaders.blobContentEncoding + ); + assert.equal( + properties.contentLanguage, + options.blobHTTPHeaders.blobContentLanguage + ); + assert.equal( + properties.contentType, + options.blobHTTPHeaders.blobContentType + ); + assert.equal(properties.metadata!.key1, options.metadata.key1); + assert.equal(properties.metadata!.key2, options.metadata.key2); + }); + + it("uploadPages", async () => { + await pageBlobURL.create(Aborter.none, 1024); + + const result = await blobURL.download(Aborter.none, 0); + assert.equal(await bodyToString(result, 1024), "\u0000".repeat(1024)); + + await pageBlobURL.uploadPages(Aborter.none, "a".repeat(512), 0, 512); + await pageBlobURL.uploadPages(Aborter.none, "b".repeat(512), 512, 512); + + const page1 = await pageBlobURL.download(Aborter.none, 0, 512); + const page2 = await pageBlobURL.download(Aborter.none, 512, 512); + + assert.equal(await bodyToString(page1, 512), "a".repeat(512)); + assert.equal(await bodyToString(page2, 512), "b".repeat(512)); + }); + + it("clearPages", async () => { + await pageBlobURL.create(Aborter.none, 1024); + let result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual( + await bodyToString(result, 1024), + "\u0000".repeat(1024) + ); + + await pageBlobURL.uploadPages(Aborter.none, "a".repeat(1024), 0, 1024); + result = await pageBlobURL.download(Aborter.none, 0, 1024); + assert.deepStrictEqual(await bodyToString(result, 1024), "a".repeat(1024)); + + await pageBlobURL.clearPages(Aborter.none, 0, 512); + result = await pageBlobURL.download(Aborter.none, 0, 512); + assert.deepStrictEqual( + await bodyToString(result, 512), + "\u0000".repeat(512) + ); + }); + + it("getPageRanges", async () => { + await pageBlobURL.create(Aborter.none, 1024); + + const result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual( + await bodyToString(result, 1024), + "\u0000".repeat(1024) + ); + + await pageBlobURL.uploadPages(Aborter.none, "a".repeat(512), 0, 512); + await pageBlobURL.uploadPages(Aborter.none, "b".repeat(512), 512, 512); + + const page1 = await pageBlobURL.getPageRanges(Aborter.none, 0, 512); + const page2 = await pageBlobURL.getPageRanges(Aborter.none, 512, 512); + + assert.equal(page1.pageRange![0].end, 511); + assert.equal(page2.pageRange![0].end, 1023); + }); + + it("getPageRangesDiff", async () => { + await pageBlobURL.create(Aborter.none, 1024); + + const result = await blobURL.download(Aborter.none, 0); + assert.deepStrictEqual( + await bodyToString(result, 1024), + "\u0000".repeat(1024) + ); + + await pageBlobURL.uploadPages(Aborter.none, "b".repeat(1024), 0, 1024); + + const snapshotResult = await pageBlobURL.createSnapshot(Aborter.none); + assert.ok(snapshotResult.snapshot); + + await pageBlobURL.uploadPages(Aborter.none, "a".repeat(512), 0, 512); + await pageBlobURL.clearPages(Aborter.none, 512, 512); + + const rangesDiff = await pageBlobURL.getPageRangesDiff( + Aborter.none, + 0, + 1024, + snapshotResult.snapshot! + ); + assert.equal(rangesDiff.pageRange![0].start, 0); + assert.equal(rangesDiff.pageRange![0].end, 511); + assert.equal(rangesDiff.clearRange![0].start, 512); + assert.equal(rangesDiff.clearRange![0].end, 1023); + }); + + it("updateSequenceNumber", async () => { + await pageBlobURL.create(Aborter.none, 1024); + let propertiesResponse = await pageBlobURL.getProperties(Aborter.none); + + await pageBlobURL.updateSequenceNumber( + Aborter.none, + Models.SequenceNumberActionType.Increment + ); + propertiesResponse = await pageBlobURL.getProperties(Aborter.none); + assert.equal(propertiesResponse.blobSequenceNumber!, 1); + + await pageBlobURL.updateSequenceNumber( + Aborter.none, + Models.SequenceNumberActionType.Update, + 10 + ); + propertiesResponse = await pageBlobURL.getProperties(Aborter.none); + assert.equal(propertiesResponse.blobSequenceNumber!, 10); + + await pageBlobURL.updateSequenceNumber( + Aborter.none, + Models.SequenceNumberActionType.Max, + 100 + ); + propertiesResponse = await pageBlobURL.getProperties(Aborter.none); + assert.equal(propertiesResponse.blobSequenceNumber!, 100); + }); +}); diff --git a/file/test/serviceurl.test.ts b/file/test/serviceurl.test.ts new file mode 100644 index 0000000..0e6c2bc --- /dev/null +++ b/file/test/serviceurl.test.ts @@ -0,0 +1,218 @@ +import * as assert from "assert"; + +import { Aborter } from "../lib/Aborter"; +import { ContainerURL } from "../lib/ContainerURL"; +import { + LeaseStateType, + LeaseStatusType, + ListContainersIncludeType +} from "../lib/generated/models"; +import { ServiceURL } from "../lib/ServiceURL"; +import { getAlternateBSU, getBSU, getUniqueName, wait } from "./utils"; + +describe("ServiceURL", () => { + it("ListContainers with default parameters", async () => { + const serviceURL = getBSU(); + const result = await serviceURL.listContainersSegment(Aborter.none); + assert.ok(typeof result.requestId); + assert.ok(result.requestId!.length > 0); + assert.ok(typeof result.version); + assert.ok(result.version!.length > 0); + + assert.ok(result.serviceEndpoint.length > 0); + assert.ok(result.containerItems!.length >= 0); + + if (result.containerItems!.length > 0) { + const container = result.containerItems![0]; + assert.ok(container.name.length > 0); + assert.ok(container.properties.etag.length > 0); + assert.ok(container.properties.lastModified); + } + }); + + it("ListContainers with all parameters configured", async () => { + const serviceURL = getBSU(); + + const containerNamePrefix = getUniqueName("container"); + const containerName1 = `${containerNamePrefix}x1`; + const containerName2 = `${containerNamePrefix}x2`; + const containerURL1 = ContainerURL.fromServiceURL( + serviceURL, + containerName1 + ); + const containerURL2 = ContainerURL.fromServiceURL( + serviceURL, + containerName2 + ); + await containerURL1.create(Aborter.none, { metadata: { key: "val" } }); + await containerURL2.create(Aborter.none, { metadata: { key: "val" } }); + + const result1 = await serviceURL.listContainersSegment( + Aborter.none, + undefined, + { + include: ListContainersIncludeType.Metadata, + maxresults: 1, + prefix: containerNamePrefix + } + ); + + assert.ok(result1.nextMarker); + assert.equal(result1.containerItems!.length, 1); + assert.ok(result1.containerItems![0].name.startsWith(containerNamePrefix)); + assert.ok(result1.containerItems![0].properties.etag.length > 0); + assert.ok(result1.containerItems![0].properties.lastModified); + assert.ok(!result1.containerItems![0].properties.leaseDuration); + assert.ok(!result1.containerItems![0].properties.publicAccess); + assert.deepEqual( + result1.containerItems![0].properties.leaseState, + LeaseStateType.Available + ); + assert.deepEqual( + result1.containerItems![0].properties.leaseStatus, + LeaseStatusType.Unlocked + ); + assert.deepEqual(result1.containerItems![0].metadata!.key, "val"); + + const result2 = await serviceURL.listContainersSegment( + Aborter.none, + result1.nextMarker, + { + include: ListContainersIncludeType.Metadata, + maxresults: 1, + prefix: containerNamePrefix + } + ); + + assert.ok(!result2.nextMarker); + assert.equal(result2.containerItems!.length, 1); + assert.ok(result2.containerItems![0].name.startsWith(containerNamePrefix)); + assert.ok(result2.containerItems![0].properties.etag.length > 0); + assert.ok(result2.containerItems![0].properties.lastModified); + assert.ok(!result2.containerItems![0].properties.leaseDuration); + assert.ok(!result2.containerItems![0].properties.publicAccess); + assert.deepEqual( + result2.containerItems![0].properties.leaseState, + LeaseStateType.Available + ); + assert.deepEqual( + result2.containerItems![0].properties.leaseStatus, + LeaseStatusType.Unlocked + ); + assert.deepEqual(result2.containerItems![0].metadata!.key, "val"); + + await containerURL1.delete(Aborter.none); + await containerURL2.delete(Aborter.none); + }); + + it("GetProperties", async () => { + const serviceURL = getBSU(); + const result = await serviceURL.getProperties(Aborter.none); + + assert.ok(typeof result.requestId); + assert.ok(result.requestId!.length > 0); + assert.ok(typeof result.version); + assert.ok(result.version!.length > 0); + + if (result.cors && result.cors!.length > 0) { + assert.ok(result.cors![0].allowedHeaders.length > 0); + assert.ok(result.cors![0].allowedMethods.length > 0); + assert.ok(result.cors![0].allowedOrigins.length > 0); + assert.ok(result.cors![0].exposedHeaders.length > 0); + assert.ok(result.cors![0].maxAgeInSeconds >= 0); + } + }); + + it("SetProperties", async () => { + const serviceURL = getBSU(); + + const serviceProperties = await serviceURL.getProperties(Aborter.none); + + serviceProperties.logging = { + deleteProperty: true, + read: true, + retentionPolicy: { + days: 5, + enabled: true + }, + version: "1.0", + write: true + }; + + serviceProperties.minuteMetrics = { + enabled: true, + includeAPIs: true, + retentionPolicy: { + days: 4, + enabled: true + }, + version: "1.0" + }; + + serviceProperties.hourMetrics = { + enabled: true, + includeAPIs: true, + retentionPolicy: { + days: 3, + enabled: true + }, + version: "1.0" + }; + + const newCORS = { + allowedHeaders: "*", + allowedMethods: "GET", + allowedOrigins: "example.com", + exposedHeaders: "*", + maxAgeInSeconds: 8888 + }; + if (!serviceProperties.cors) { + serviceProperties.cors = [newCORS]; + } else if (serviceProperties.cors!.length < 5) { + serviceProperties.cors.push(newCORS); + } + + if (!serviceProperties.deleteRetentionPolicy) { + serviceProperties.deleteRetentionPolicy = { + days: 2, + enabled: false + }; + } + + await serviceURL.setProperties(Aborter.none, serviceProperties); + await wait(5 * 1000); + + const result = await serviceURL.getProperties(Aborter.none); + assert.ok(typeof result.requestId); + assert.ok(result.requestId!.length > 0); + assert.ok(typeof result.version); + assert.ok(result.version!.length > 0); + assert.deepEqual(result.hourMetrics, serviceProperties.hourMetrics); + }); + + it("getStatistics", done => { + let serviceURL: ServiceURL | undefined; + try { + serviceURL = getAlternateBSU(); + } catch (err) { + done(); + return; + } + + serviceURL! + .getStatistics(Aborter.none) + .then(result => { + assert.ok(result.geoReplication!.lastSyncTime); + done(); + }) + .catch(done); + }); + + it("getAccountInfo", async () => { + const serviceURL = getBSU(); + + const accountInfo = await serviceURL.getAccountInfo(Aborter.none); + assert.ok(accountInfo.accountKind); + assert.ok(accountInfo.skuName); + }); +}); diff --git a/file/test/utils/index.browser.ts b/file/test/utils/index.browser.ts new file mode 100644 index 0000000..7be3f53 --- /dev/null +++ b/file/test/utils/index.browser.ts @@ -0,0 +1,135 @@ +import { AnonymousCredential } from "../../lib/credentials/AnonymousCredential"; +import { ServiceURL } from "../../lib/ServiceURL"; +import { StorageURL } from "../../lib/StorageURL"; + +export * from "./testutils.common"; + +export function getGenericBSU( + accountType: string, + accountNameSuffix: string = "" +): ServiceURL { + const accountNameEnvVar = `${accountType}ACCOUNT_NAME`; + const accountSASEnvVar = `${accountType}ACCOUNT_SAS`; + + let accountName: string | undefined; + let accountSAS: string | undefined; + accountName = (window as any).__env__[accountNameEnvVar]; + accountSAS = (window as any).__env__[accountSASEnvVar]; + + if (!accountName || !accountSAS || accountName === "" || accountSAS === "") { + throw new Error( + `${accountNameEnvVar} and/or ${accountSASEnvVar} environment variables not specified.` + ); + } + + if (accountSAS) { + accountSAS = accountSAS.startsWith("?") ? accountSAS : `?${accountSAS}`; + } + + const credentials = new AnonymousCredential(); + const pipeline = StorageURL.newPipeline(credentials, { + // Enable logger when debugging + // logger: new ConsoleHttpPipelineLogger(HttpPipelineLogLevel.INFO) + }); + const blobPrimaryURL = `https://${accountName}${accountNameSuffix}.blob.core.windows.net${accountSAS}`; + return new ServiceURL(blobPrimaryURL, pipeline); +} + +export function getBSU(): ServiceURL { + return getGenericBSU(""); +} + +export function getAlternateBSU(): ServiceURL { + return getGenericBSU("SECONDARY_", "-secondary"); +} + +/** + * Read body from downloading operation methods to string. + * Work on both Node.js and browser environment. + * + * @param response Convenience layer methods response with downloaded body + * @param length Length of Readable stream, needed for Node.js environment + */ +export async function bodyToString( + response: { + readableStreamBody?: NodeJS.ReadableStream; + blobBody?: Promise; + }, + // tslint:disable-next-line:variable-name + _length?: number +): Promise { + const blob = await response.blobBody!; + return blobToString(blob); +} + +export async function blobToString(blob: Blob): Promise { + const fileReader = new FileReader(); + return new Promise((resolve, reject) => { + fileReader.onloadend = (ev: any) => { + resolve(ev.target!.result); + }; + fileReader.onerror = reject; + fileReader.readAsText(blob); + }); +} + +export async function blobToArrayBuffer(blob: Blob): Promise { + const fileReader = new FileReader(); + return new Promise((resolve, reject) => { + fileReader.onloadend = (ev: any) => { + resolve(ev.target!.result); + }; + fileReader.onerror = reject; + fileReader.readAsArrayBuffer(blob); + }); +} + +export function arrayBufferEqual( + buf1: ArrayBuffer, + buf2: ArrayBuffer +): boolean { + if (buf1.byteLength !== buf2.byteLength) { + return false; + } + + const uint8Arr1 = new Uint8Array(buf1); + const uint8Arr2 = new Uint8Array(buf2); + + for (let i = 0; i <= uint8Arr1.length; i++) { + if (uint8Arr1[i] !== uint8Arr2[i]) { + return false; + } + } + + return true; +} + +export function isIE(): boolean { + const sAgent = window.navigator.userAgent; + const Idx = sAgent.indexOf("MSIE"); + + // If IE, return version number. + if (Idx > 0) { + return true; + } else if (!!navigator.userAgent.match(/Trident\/7\./)) { + // IE 11 + return true; + } else { + return false; + } // It is not IE +} + +// Mock a Browser file with specified name and size +export function getBrowserFile(name: string, size: number): File { + const uint8Arr = new Uint8Array(size); + for (let j = 0; j < size; j++) { + uint8Arr[j] = Math.floor(Math.random() * 256); + } + + // IE11 & Edge doesn't support create File using var file = new File([binary], name); + // We leverage Blob() to mock a File + + const file = new Blob([uint8Arr]) as any; + file.name = name; + return file; +} diff --git a/file/test/utils/index.ts b/file/test/utils/index.ts new file mode 100644 index 0000000..0088027 --- /dev/null +++ b/file/test/utils/index.ts @@ -0,0 +1,124 @@ +import * as crypto from "crypto"; +import * as fs from "fs"; +import * as path from "path"; + +import { SharedKeyCredential } from "../../lib/credentials/SharedKeyCredential"; +import { ServiceURL } from "../../lib/ServiceURL"; +import { StorageURL } from "../../lib/StorageURL"; +import { getUniqueName } from "./testutils.common"; + +export * from "./testutils.common"; + +export function getGenericBSU( + accountType: string, + accountNameSuffix: string = "" +): ServiceURL { + const accountNameEnvVar = `${accountType}ACCOUNT_NAME`; + const accountKeyEnvVar = `${accountType}ACCOUNT_KEY`; + + let accountName: string | undefined; + let accountKey: string | undefined; + + accountName = process.env[accountNameEnvVar]; + accountKey = process.env[accountKeyEnvVar]; + + if (!accountName || !accountKey || accountName === "" || accountKey === "") { + throw new Error( + `${accountNameEnvVar} and/or ${accountKeyEnvVar} environment variables not specified.` + ); + } + + const credentials = new SharedKeyCredential(accountName, accountKey); + const pipeline = StorageURL.newPipeline(credentials, { + // Enable logger when debugging + // logger: new ConsoleHttpPipelineLogger(HttpPipelineLogLevel.INFO) + }); + const blobPrimaryURL = `https://${accountName}${accountNameSuffix}.blob.core.windows.net/`; + return new ServiceURL(blobPrimaryURL, pipeline); +} + +export function getBSU(): ServiceURL { + return getGenericBSU(""); +} + +export function getAlternateBSU(): ServiceURL { + return getGenericBSU("SECONDARY_", "-secondary"); +} + +/** + * Read body from downloading operation methods to string. + * Work on both Node.js and browser environment. + * + * @param response Convenience layer methods response with downloaded body + * @param length Length of Readable stream, needed for Node.js environment + */ +export async function bodyToString( + response: { + readableStreamBody?: NodeJS.ReadableStream; + blobBody?: Promise; + }, + length?: number +): Promise { + return new Promise((resolve, reject) => { + response.readableStreamBody!.on("readable", () => { + let chunk; + chunk = response.readableStreamBody!.read(length); + if (chunk) { + resolve(chunk.toString()); + } + }); + + response.readableStreamBody!.on("error", reject); + }); +} + +export async function createRandomLocalFile( + folder: string, + blockNumber: number, + blockSize: number +): Promise { + return new Promise((resolve, reject) => { + const destFile = path.join(folder, getUniqueName("tempfile.")); + const ws = fs.createWriteStream(destFile); + let offsetInMB = 0; + + function randomValueHex(len = blockSize) { + return crypto + .randomBytes(Math.ceil(len / 2)) + .toString("hex") // convert to hexadecimal format + .slice(0, len); // return required number of characters + } + + ws.on("open", () => { + // tslint:disable-next-line:no-empty + while (offsetInMB++ < blockNumber && ws.write(randomValueHex())) {} + if (offsetInMB >= blockNumber) { + ws.end(); + } + }); + + ws.on("drain", () => { + // tslint:disable-next-line:no-empty + while (offsetInMB++ < blockNumber && ws.write(randomValueHex())) {} + if (offsetInMB >= blockNumber) { + ws.end(); + } + }); + ws.on("finish", () => resolve(destFile)); + ws.on("error", reject); + }); +} + +export async function readStreamToLocalFile( + rs: NodeJS.ReadableStream, + file: string +) { + return new Promise((resolve, reject) => { + const ws = fs.createWriteStream(file); + rs.pipe(ws); + rs.on("error", reject); + ws.on("error", reject); + ws.on("finish", resolve); + rs.on("end", resolve); + }); +} diff --git a/file/test/utils/testutils.common.ts b/file/test/utils/testutils.common.ts new file mode 100644 index 0000000..93994a0 --- /dev/null +++ b/file/test/utils/testutils.common.ts @@ -0,0 +1,59 @@ +import { HttpPipelineLogLevel, IHttpPipelineLogger } from "../../lib/Pipeline"; +import { padStart } from "../../lib/utils/utils.common"; + +export function isBrowser(): boolean { + return typeof window !== "undefined"; +} + +export function getUniqueName(prefix: string): string { + return `${prefix}${new Date().getTime()}${padStart( + Math.floor(Math.random() * 10000).toString(), + 5, + "00000" + )}`; +} + +export async function sleep(time: number): Promise { + return new Promise(resolve => { + setTimeout(resolve, time); + }); +} + +export function base64encode(content: string): string { + return isBrowser() ? btoa(content) : Buffer.from(content).toString("base64"); +} + +export function base64decode(encodedString: string): string { + return isBrowser() + ? atob(encodedString) + : Buffer.from(encodedString, "base64").toString(); +} + +export class ConsoleHttpPipelineLogger implements IHttpPipelineLogger { + constructor(public minimumLogLevel: HttpPipelineLogLevel) {} + public log(logLevel: HttpPipelineLogLevel, message: string): void { + const logMessage = `${new Date().toISOString()} ${ + HttpPipelineLogLevel[logLevel] + }: ${message}`; + switch (logLevel) { + case HttpPipelineLogLevel.ERROR: + // tslint:disable-next-line:no-console + console.error(logMessage); + break; + case HttpPipelineLogLevel.WARNING: + // tslint:disable-next-line:no-console + console.warn(logMessage); + break; + case HttpPipelineLogLevel.INFO: + // tslint:disable-next-line:no-console + console.log(logMessage); + break; + } + } +} + +export async function wait(time: number): Promise { + return new Promise(resolve => { + setTimeout(resolve, time); + }); +} diff --git a/file/tsconfig.json b/file/tsconfig.json new file mode 100644 index 0000000..3894242 --- /dev/null +++ b/file/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "alwaysStrict": true, + "noImplicitAny": true, + "preserveConstEnums": true, + "sourceMap": true, + "newLine": "LF", + "target": "es5", + "moduleResolution": "node", + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true, + "module": "esNext", + "outDir": "./dist-esm", + "declaration": true, + "declarationMap": true, + "importHelpers": true, + "declarationDir": "./typings", + "lib": ["dom", "es5", "es6", "es7", "esnext"], + "esModuleInterop": true + }, + "compileOnSave": true, + "exclude": ["node_modules"], + "include": ["./lib/**/*.ts", "./test/**/*.ts"] +} diff --git a/file/tslint.json b/file/tslint.json new file mode 100644 index 0000000..1a72ca1 --- /dev/null +++ b/file/tslint.json @@ -0,0 +1,13 @@ +{ + "defaultSeverity": "error", + "extends": ["tslint:recommended"], + "jsRules": {}, + "rules": { + "trailing-comma": false, + "arrow-parens": false + }, + "rulesDirectory": [], + "linterOptions": { + "exclude": ["lib/generated/**"] + } +}