From 28e7fafcf1af1b42f3f1284cc1d743b170032259 Mon Sep 17 00:00:00 2001 From: Walson Low Date: Mon, 5 Dec 2022 16:42:21 +0800 Subject: [PATCH 1/2] Fix ItemsMap doesn't match real object (fixes #1187) Multiple reads after tasks have been fetched causes folder index to be misaligned. This fix forces fetched tasks to be queued, ensuring that task handlers finish committing their changes before running the next task handler. --- release/remotestorage.js | 12253 ++++++++++++++++++++++++++++++++- release/remotestorage.js.map | 2 +- src/sync.ts | 25 +- 3 files changed, 12272 insertions(+), 8 deletions(-) diff --git a/release/remotestorage.js b/release/remotestorage.js index 924dc232a..573cfd88f 100644 --- a/release/remotestorage.js +++ b/release/remotestorage.js @@ -1,14 +1,3873 @@ -/*! remotestorage.js 2.0.0-beta.5, https://remotestorage.io, MIT licensed */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("RemoteStorage",[],t):"object"==typeof exports?exports.RemoteStorage=t():e.RemoteStorage=t()}(this,(function(){return function(e){var t={};function r(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=e,r.c=t,r.d=function(e,t,o){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(r.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)r.d(o,n,function(t){return e[t]}.bind(null,n));return o},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=18)}([function(e,t,r){"use strict";(function(e,r){var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))};Object.defineProperty(t,"__esModule",{value:!0}),t.applyMixins=t.generateCodeVerifier=t.toBase64=t.getTextFromArrayBuffer=t.shouldBeTreatedAsBinary=t.getJSONFromLocalStorage=t.localStorageAvailable=t.pathsFromRoot=t.deepClone=t.equal=t.bindAll=t.cleanPath=t.baseName=t.isDocument=t.isFolder=t.containingFolder=t.extend=t.getGlobalContext=t.globalContext=t.logError=void 0;t.logError=e=>{"string"==typeof e?console.error(e):console.error(e.message,e.stack)},t.globalContext="undefined"!=typeof window?window:"object"==typeof self?self:e;t.getGlobalContext=()=>"undefined"!=typeof window?window:"object"==typeof self?self:e;t.extend=(...e)=>{const t=e[0];return Array.prototype.slice.call(e,1).forEach((function(e){for(const r in e)t[r]=e[r]})),t};t.containingFolder=e=>{if(""===e)return"/";if(!e)throw"Path not given!";return e.replace(/\/+/g,"/").replace(/[^\/]+\/?$/,"")};t.isFolder=e=>"/"===e.slice(-1);t.isDocument=e=>!(0,t.isFolder)(e);t.baseName=e=>{const r=e.split("/");return(0,t.isFolder)(e)?r[r.length-2]+"/":r[r.length-1]};t.cleanPath=e=>e.replace(/\/+/g,"/").split("/").map(encodeURIComponent).join("/").replace(/'/g,"%27");t.bindAll=e=>{for(const t in this)"function"==typeof e[t]&&(e[t]=e[t].bind(e))};t.equal=(e,r,o=[])=>{let n;if(typeof e!=typeof r)return!1;if("number"==typeof e||"boolean"==typeof e||"string"==typeof e)return e===r;if("function"==typeof e)return e.toString()===r.toString();if(e instanceof ArrayBuffer&&r instanceof ArrayBuffer&&(e=new Uint8Array(e),r=new Uint8Array(r)),e instanceof Array){if(e.length!==r.length)return!1;for(let n=0,i=e.length;n=0)continue;i=o.slice(),i.push(r[n])}if(!(0,t.equal)(e[n],r[n],i))return!1}}return!0};t.deepClone=e=>{if(void 0!==e){const t=JSON.parse(JSON.stringify(e));return function e(t,r){if("object"==typeof t&&!Array.isArray(t)&&null!==t)for(const o in t)if("object"==typeof t[o]&&null!==t[o])if("[object ArrayBuffer]"===t[o].toString()){r[o]=new ArrayBuffer(t[o].byteLength);const e=new Int8Array(t[o]);new Int8Array(r[o]).set(e)}else e(t[o],r[o])}(e,t),t}};t.pathsFromRoot=e=>{const t=[e],r=e.replace(/\/$/,"").split("/");for(;r.length>1;)r.pop(),t.push(r.join("/")+"/");return t};t.localStorageAvailable=()=>{const e=(0,t.getGlobalContext)();if(!("localStorage"in e))return!1;try{return e.localStorage.setItem("rs-check","1"),e.localStorage.removeItem("rs-check"),!0}catch(e){return!1}};t.getJSONFromLocalStorage=e=>{const r=(0,t.getGlobalContext)();try{return JSON.parse(r.localStorage.getItem(e))}catch(e){}};t.shouldBeTreatedAsBinary=(e,t)=>!!(t&&t.match(/charset=binary/)||/[\x00-\x08\x0E-\x1F\uFFFD]/.test(e));t.getTextFromArrayBuffer=(e,o)=>new Promise(n=>{if("undefined"==typeof Blob){const t=r.from(e);n(t.toString(o))}else{let r;const i=t.globalContext;if(i.BlobBuilder=i.BlobBuilder||i.WebKitBlobBuilder,void 0!==i.BlobBuilder){const t=new i.BlobBuilder;t.append(e),r=t.getBlob()}else r=new Blob([e]);const s=new FileReader;"function"==typeof s.addEventListener?s.addEventListener("loadend",(function(e){n(e.target.result)})):s.onloadend=function(e){n(e.target.result)},s.readAsText(r,o)}});t.toBase64=e=>{const o=(0,t.getGlobalContext)();return"btoa"in o?o.btoa(e):r.from(e).toString("base64")},t.generateCodeVerifier=function(e=128){return o(this,void 0,void 0,(function*(){const t=new Uint8Array(e);crypto.getRandomValues(t);const r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",o=Array.from(t).map(e=>r[e%r.length]),n=o.join(""),i=Uint8Array.from(o.map(e=>e.charCodeAt(0))),s=yield crypto.subtle.digest("SHA-256",i),a=(u=s,btoa(String.fromCharCode.apply(null,new Uint8Array(u))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""));var u;crypto.getRandomValues(t);return{codeVerifier:n,codeChallenge:a,state:Array.from(t).map(e=>r[e%r.length]).join("")}}))},t.applyMixins=function(e,t){t.forEach(t=>{Object.getOwnPropertyNames(t.prototype).forEach(r=>{Object.defineProperty(e.prototype,r,Object.getOwnPropertyDescriptor(t.prototype,r))})})}}).call(this,r(6),r(20).Buffer)},function(e,t,r){"use strict";const o=(this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(r(3));e.exports=function(...e){o.default.logging&&console.log(...e)}},function(e,t,r){"use strict";const o=(this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(r(1));e.exports=class{addEvents(e){e.forEach(e=>this._addEvent(e))}addEventListener(e,t){if("string"!=typeof e)throw new Error("Argument eventName should be a string");if("function"!=typeof t)throw new Error("Argument handler should be a function");(0,o.default)("[EventHandling] Adding event listener",e),this._validateEvent(e),this._handlers[e].push(t)}on(e,t){return this.addEventListener(e,t)}removeEventListener(e,t){this._validateEvent(e);const r=this._handlers[e].length;for(let o=0;o{e.apply(this,t)})}_validateEvent(e){if(!(e in this._handlers))throw new Error("Unknown event: "+e)}_delegateEvent(e,t){t.on(e,t=>{this._emit(e,t)})}_addEvent(e){void 0===this._handlers&&(this._handlers={}),this._handlers[e]=[]}}},function(e,t,r){"use strict";const o={cache:!0,changeEvents:{local:!0,window:!1,remote:!0,conflict:!0},cordovaRedirectUri:void 0,logging:!1,modules:[],backgroundSyncInterval:6e4,disableFeatures:[],discoveryTimeout:1e4,isBackground:!1,requestTimeout:3e4,syncInterval:1e4};e.exports=o},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(1)),s=r(0),a=n(r(5)),u=r(7);let c;function h(e){const t=e||l.getLocation().href,r={};for(const[e,o]of new URL(t).searchParams)r[e]=o;const o=t.indexOf("#");if(-1===o)return r;const n=t.substring(o+1);return n.includes("=")?n.split("&").reduce((function(e,t){const r=t.split("=");if("state"===r[0]&&r[1].match(/rsDiscovery/)){let t=decodeURIComponent(r[1]);const o=t.substr(t.indexOf("rsDiscovery=")).split("&")[0].split("=")[1];e.rsDiscovery=JSON.parse(atob(o)),t=t.replace(new RegExp("&?rsDiscovery="+o),""),t.length>0&&(e.state=t)}else e[decodeURIComponent(r[0])]=decodeURIComponent(r[1]);return e}),r):r}class l{static authorize(e,t){if((0,i.default)("[Authorize] authURL = ",t.authURL,"scope = ",t.scope,"redirectUri = ",t.redirectUri,"clientId = ",t.clientId,"response_type =",t.response_type),!t.scope)throw new Error("Cannot authorize due to undefined or empty scope; did you forget to access.claim()?");if(!(0,s.localStorageAvailable)()&&"remotestorage"===e.backend){t.redirectUri+=t.redirectUri.indexOf("#")>0?"&":"#";const r={userAddress:e.remote.userAddress,href:e.remote.href,storageApi:e.remote.storageApi,properties:e.remote.properties};t.redirectUri+="rsDiscovery="+(0,s.toBase64)(JSON.stringify(r))}const r=function(e){const t=new URL(e.redirectUri);e.state||(e.state=t.hash?t.hash.substring(1):""),e.response_type||(e.response_type="token");const r=new URL(e.authURL);r.searchParams.set("redirect_uri",e.redirectUri.replace(/#.*$/,"")),r.searchParams.set("scope",e.scope),r.searchParams.set("client_id",e.clientId);for(const t of["state","response_type","code_challenge","code_challenge_method","token_access_type"]){const o=e[t];o&&r.searchParams.set(t,o)}return r.href}(t);s.globalContext.cordova?l.openWindow(r,t.redirectUri,"location=yes,clearsessioncache=yes,clearcache=yes").then(t=>{e.remote.configure({token:t.access_token})}):l.setLocation(r)}static refreshAccessToken(e,t,r){var n,s,c;return o(this,void 0,void 0,(function*(){yield t.configure({token:null,tokenType:null});const e=new URLSearchParams({grant_type:"refresh_token",client_id:t.clientId,refresh_token:r}),o=yield(0,u.requestWithTimeout)("POST",t.TOKEN_URL,{headers:{"Content-Type":"application/x-www-form-urlencoded"},body:e.toString(),responseType:"json"});if(200!==(null==o?void 0:o.status))throw yield t.configure({refreshToken:null}),new a.default("refresh token rejected:"+JSON.stringify(o.response));{(0,i.default)(`[Authorize] access token good for ${null===(n=null==o?void 0:o.response)||void 0===n?void 0:n.expires_in} seconds`);const e={token:null===(s=null==o?void 0:o.response)||void 0===s?void 0:s.access_token,tokenType:null===(c=null==o?void 0:o.response)||void 0===c?void 0:c.token_type};if(!e.token)throw new Error('no access_token in "successful" refresh: '+o.response);yield t.configure(e)}}))}static setLocation(e){if("string"==typeof e)document.location.href=e;else{if("object"!=typeof e)throw"Invalid location "+e;document.location=e}}static _rs_supported(){return"undefined"!=typeof document}static _rs_cleanup(e){e.removeEventListener("features-loaded",c)}}l.IMPLIED_FAKE_TOKEN=!1,l.getLocation=function(){return document.location},l.openWindow=function(e,t,r){return new Promise((o,n)=>{const i=open(e,"_blank",r);function s(){n("Authorization was canceled")}i&&!i.closed?(i.addEventListener("loadstart",(function(e){if(0!==e.url.indexOf(t))return;i.removeEventListener("exit",s),i.close();const r=h(e.url);r?o(r):n("Authorization error")})),i.addEventListener("exit",s)):n("Authorization popup was blocked")})},l._rs_init=function(e){const t=h();let r;t&&(r=l.getLocation(),r.hash=""),c=function(){let n=!1;if(t){if(t.error)throw"access_denied"===t.error?new a.default("Authorization failed: access denied",{code:"access_denied"}):new a.default("Authorization failed: "+t.error);t.rsDiscovery&&e.remote.configure(t.rsDiscovery),t.access_token&&(e.remote.configure({token:t.access_token}),n=!0),t.remotestorage&&(e.connect(t.remotestorage),n=!0),t.state&&(r=l.getLocation(),l.setLocation(r.href.split("#")[0]+"#"+t.state)),t.code&&(!function(t){var n,s,a,c;o(this,void 0,void 0,(function*(){const o=sessionStorage.getItem("remotestorage:codeVerifier");if(!o)return void(0,i.default)("[Authorize] Ignoring OAuth code parameter, because no PKCE code verifier found in sessionStorage");r=l.getLocation();let h=r.origin;"/"!==r.pathname&&(h+=r.pathname);const d=new URLSearchParams({code:t,grant_type:"authorization_code",client_id:e.remote.clientId,redirect_uri:h,code_verifier:o}),f=yield(0,u.requestWithTimeout)("POST",e.remote.TOKEN_URL,{headers:{"Content-Type":"application/x-www-form-urlencoded"},body:d.toString(),responseType:"json"});switch(f.status){case 200:(0,i.default)(`[Authorize] access token good for ${null===(n=null==f?void 0:f.response)||void 0===n?void 0:n.expires_in} seconds`);const t={token:null===(s=null==f?void 0:f.response)||void 0===s?void 0:s.access_token,refreshToken:null===(a=null==f?void 0:f.response)||void 0===a?void 0:a.refresh_token,tokenType:null===(c=null==f?void 0:f.response)||void 0===c?void 0:c.token_type};t.token?e.remote.configure(t):e._emit("error",new Error('no access_token in "successful" response: '+f.response)),sessionStorage.removeItem("remotestorage:codeVerifier");break;default:e._emit("error",new Error(`${f.statusText}: ${f.response}`))}}))}(t.code),n=!0),n||e.remote.stopWaitingForToken()}else e.remote.stopWaitingForToken()},e.on("features-loaded",c)},e.exports=l},function(e,t,r){"use strict";class o extends Error{constructor(e,t={}){super(),this.name="Unauthorized",this.message=void 0===e?"App authorization expired or revoked.":e,void 0!==t.code&&(this.code=t.code),this.stack=(new Error).stack}}e.exports=o},function(e,t){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(e){"object"==typeof window&&(r=window)}e.exports=r},function(e,t,r){"use strict";(function(e){var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.requestWithTimeout=t.isArrayBufferView=t.retryAfterMs=void 0;const i=n(r(1)),s=n(r(3));if(t.retryAfterMs=function(e){const t=1e3*parseInt(e.getResponseHeader("Retry-After"));return t>=1e3?t:Math.max(1500,Math.min(6e4,Math.round(s.default.syncInterval/(2.9+.2*Math.random()))))},"function"==typeof(e||window).ArrayBufferView)t.isArrayBufferView=function(t){return t&&t instanceof(e||window).ArrayBufferView};else{const e=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];t.isArrayBufferView=function(t){for(let r=0;r<8;r++)if(t instanceof e[r])return!0;return!1}}t.requestWithTimeout=function(e,r,n){return o(this,void 0,void 0,(function*(){return"function"==typeof fetch?function(e,t,r){return o(this,void 0,void 0,(function*(){const o="function"==typeof AbortController?new AbortController:null;let n;const a=new Promise((e,t)=>{n=setTimeout(()=>{o&&o.abort(),t("timeout")},s.default.requestTimeout)});let u;const c={},h=fetch(t,{method:e,headers:r.headers,body:r.body,signal:o?o.signal:void 0}).then(e=>{switch((0,i.default)("[requests fetch]",e),e.headers.forEach((e,t)=>{c[t.toUpperCase()]=e}),u={readyState:4,status:e.status,statusText:e.statusText,response:void 0,getResponseHeader:e=>c[e.toUpperCase()]||null,responseType:r.responseType,responseURL:t},r.responseType){case"arraybuffer":return e.arrayBuffer();case"blob":return e.blob();case"json":return e.json();case void 0:case"":case"text":return e.text();default:throw new Error("responseType 'document' is not currently supported using fetch")}}).then(e=>(u.response=e,r.responseType&&"text"!==r.responseType||(u.responseText=e),u)).finally(()=>{clearTimeout(n)});return Promise.race([h,a])}))}(e,r,n):"function"==typeof XMLHttpRequest?function(e,r,n){return o(this,void 0,void 0,(function*(){return new Promise((o,a)=>{(0,i.default)("[requests XHR]",e,r);let u=!1;const c=setTimeout(()=>{u=!0,a("timeout")},s.default.requestTimeout),h=new XMLHttpRequest;if(h.open(e,r,!0),n.responseType&&(h.responseType=n.responseType),n.headers)for(const e in n.headers)h.setRequestHeader(e,n.headers[e]);h.onload=()=>{u||(clearTimeout(c),o(h))},h.onerror=e=>{u||(clearTimeout(c),a(e))};let l=n.body;"object"==typeof l&&!(0,t.isArrayBufferView)(l)&&l instanceof ArrayBuffer&&(l=new Uint8Array(l)),h.send(l)})}))}(e,r,n):Promise.reject("[Requests] You need to add a polyfill for fetch or XMLHttpRequest")}))}}).call(this,r(6))},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(24)),s=n(r(25)),a=n(r(26)),u=n(r(2)),c=n(r(3)),h=r(0);class l{constructor(e,t){if(this.schemas={configurable:!0,get(){return l.Types.inScope(this.moduleName)}},"/"!==t[t.length-1])throw"Not a folder: "+t;"/"===t&&(this.makePath=e=>("/"===e[0]?"":"/")+e),this.storage=e,this.base=t,this.moduleName=function(e){const t=e.split("/");return e.length>2?t[1]:"root"}(this.base),this.addEvents(["change"]),this.on=this.on.bind(this),e.onChange(this.base,this._fireChange.bind(this))}scope(e){return new l(this.storage,this.makePath(e))}getListing(e,t){return o(this,void 0,void 0,(function*(){if("string"!=typeof e)e="";else if(e.length>0&&!(0,h.isFolder)(e))return Promise.reject("Not a folder: "+e);return this.storage.get(this.makePath(e),t).then(e=>404===e.statusCode?{}:e.body)}))}getAll(e,t){return o(this,void 0,void 0,(function*(){if("string"!=typeof e)e="";else if(e.length>0&&!(0,h.isFolder)(e))return Promise.reject("Not a folder: "+e);return this.storage.get(this.makePath(e),t).then(r=>{if(404===r.statusCode)return{};if("object"==typeof r.body){const o=Object.keys(r.body);if(0===o.length)return{};const n=o.map(o=>this.storage.get(this.makePath(e+o),t).then(e=>{if("string"==typeof e.body)try{e.body=JSON.parse(e.body)}catch(e){}"object"==typeof e.body&&(r.body[o]=e.body)}));return Promise.all(n).then(()=>r.body)}})}))}getFile(e,t){return o(this,void 0,void 0,(function*(){return"string"!=typeof e?Promise.reject("Argument 'path' of baseClient.getFile must be a string"):this.storage.get(this.makePath(e),t).then(e=>({data:e.body,contentType:e.contentType,revision:e.revision}))}))}storeFile(e,t,r){return o(this,void 0,void 0,(function*(){return"string"!=typeof e?Promise.reject("Argument 'mimeType' of baseClient.storeFile must be a string"):"string"!=typeof t?Promise.reject("Argument 'path' of baseClient.storeFile must be a string"):"string"!=typeof r&&"object"!=typeof r?Promise.reject("Argument 'body' of baseClient.storeFile must be a string, ArrayBuffer, or ArrayBufferView"):(this.storage.access.checkPathPermission(this.makePath(t),"rw")||console.warn("WARNING: Editing a document to which only read access ('r') was claimed"),this.storage.put(this.makePath(t),r,e).then(e=>200===e.statusCode||201===e.statusCode?e.revision:Promise.reject("Request (PUT "+this.makePath(t)+") failed with status: "+e.statusCode)))}))}getObject(e,t){return o(this,void 0,void 0,(function*(){return"string"!=typeof e?Promise.reject("Argument 'path' of baseClient.getObject must be a string"):this.storage.get(this.makePath(e),t).then(t=>{if("object"==typeof t.body)return t.body;if("string"==typeof t.body)try{return JSON.parse(t.body)}catch(t){throw new Error("Not valid JSON: "+this.makePath(e))}else if(void 0!==t.body&&200===t.statusCode)return Promise.reject("Not an object: "+this.makePath(e))})}))}storeObject(e,t,r){return o(this,void 0,void 0,(function*(){if("string"!=typeof e)return Promise.reject("Argument 'typeAlias' of baseClient.storeObject must be a string");if("string"!=typeof t)return Promise.reject("Argument 'path' of baseClient.storeObject must be a string");if("object"!=typeof r)return Promise.reject("Argument 'object' of baseClient.storeObject must be an object");this._attachType(r,e);try{const e=this.validate(r);if(!e.valid)return Promise.reject(e)}catch(e){return Promise.reject(e)}return this.storage.put(this.makePath(t),JSON.stringify(r),"application/json; charset=UTF-8").then(e=>200===e.statusCode||201===e.statusCode?e.revision:Promise.reject("Request (PUT "+this.makePath(t)+") failed with status: "+e.statusCode))}))}remove(e){return"string"!=typeof e?Promise.reject("Argument 'path' of baseClient.remove must be a string"):(this.storage.access.checkPathPermission(this.makePath(e),"rw")||console.warn("WARNING: Removing a document to which only read access ('r') was claimed"),this.storage.delete(this.makePath(e)))}getItemURL(e){if("string"!=typeof e)throw"Argument 'path' of baseClient.getItemURL must be a string";return this.storage.connected?(e=(0,h.cleanPath)(this.makePath(e)),this.storage.remote.href+e):void 0}cache(e,t="ALL"){if("string"!=typeof e)throw"Argument 'path' of baseClient.cache must be a string";if("string"!=typeof t)throw"Argument 'strategy' of baseClient.cache must be a string or undefined";if("FLUSH"!==t&&"SEEN"!==t&&"ALL"!==t)throw'Argument \'strategy\' of baseclient.cache must be one of ["FLUSH", "SEEN", "ALL"]';return this.storage.caching.set(this.makePath(e),t),this}flush(e){return this.storage.local.flush(e)}declareType(e,t,r){let o;if(r&&"string"==typeof t)o=t;else if(r||"string"==typeof t){if(!r&&"string"==typeof t)throw new Error("declareType() requires a JSON Schema object to be passed, in order to validate object types/formats")}else r=t,o=this._defaultTypeURI(e);l.Types.declare(this.moduleName,e,o,r)}validate(e){const t=l.Types.getSchema(e["@context"]);if(t)return i.default.validateResult(e,t);throw new a.default(e["@context"])}_defaultTypeURI(e){return"http://remotestorage.io/spec/modules/"+encodeURIComponent(this.moduleName)+"/"+encodeURIComponent(e)}_attachType(e,t){e["@context"]=l.Types.resolveAlias(this.moduleName+"/"+t)||this._defaultTypeURI(t)}makePath(e){return this.base+(e||"")}_fireChange(e){c.default.changeEvents[e.origin]&&(["new","old","lastCommon"].forEach((function(t){if((!e[t+"ContentType"]||/^application\/(.*)json(.*)/.exec(e[t+"ContentType"]))&&"string"==typeof e[t+"Value"])try{e[t+"Value"]=JSON.parse(e[t+"Value"])}catch(e){}})),this._emit("change",e))}static _rs_init(){}}l.Types=s.default,(0,h.applyMixins)(l,[u.default]),e.exports=l},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.RemoteBase=void 0;const n=o(r(2)),i=r(0);class s extends n.default{constructor(e){super(),this.rs=e,this.connected=!1}stopWaitingForToken(){this.connected||this._emit("not-connected")}addQuotes(e){return"string"!=typeof e?e:"*"===e?"*":'"'+e+'"'}stripQuotes(e){return"string"!=typeof e?e:e.replace(/^["']|["']$/g,"")}isForbiddenRequestMethod(e,t){return("PUT"===e||"DELETE"===e)&&(0,i.isFolder)(t)}}t.RemoteBase=s},function(e,t,r){"use strict";class o extends Error{constructor(e){super(),this.name="SyncError",this.message="Sync failed: ","string"==typeof e?this.message+=e:(this.message+=e.message,this.stack=e.stack,this.originalError=e)}}e.exports=o},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(2)),s=n(r(3)),a=n(r(1)),u=r(0);function c(e){if("object"==typeof e&&"string"==typeof e.path)if((0,u.isFolder)(e.path)){if(e.local&&e.local.itemsMap)return e.local;if(e.common&&e.common.itemsMap)return e.common}else{if(e.local){if(e.local.body&&e.local.contentType)return e.local;if(!1===e.local.body)return}if(e.common&&e.common.body&&e.common.contentType)return e.common;if(e.body&&e.contentType)return{body:e.body,contentType:e.contentType}}}function h(e,t){for(const r in e){if(e[r]&&e[r].remote)return!0;const o=c(e[r]);if(o&&o.timestamp&&(new Date).getTime()-o.timestamp<=t)return!1;if(!o)return!0}return!0}function l(e){const t={path:e,common:{}};return(0,u.isFolder)(e)&&(t.common.itemsMap={}),t}function d(e,t){return e.common||(e.common={itemsMap:{}}),e.common.itemsMap||(e.common.itemsMap={}),e.local||(e.local=(0,u.deepClone)(e.common)),e.local.itemsMap||(e.local.itemsMap=e.common.itemsMap),e.local.itemsMap[t]=!0,e}class f{constructor(){this._updateNodesRunning=!1,this._updateNodesQueued=[]}get(e,t,r){return o(this,void 0,void 0,(function*(){return"number"==typeof t?this.getNodes((0,u.pathsFromRoot)(e)).then(o=>{const n=c(o[e]);return h(o,t)?r(e):n?{statusCode:200,body:n.body||n.itemsMap,contentType:n.contentType}:{statusCode:404}}):this.getNodes([e]).then(t=>{const r=c(t[e]);if(r){if((0,u.isFolder)(e))for(const e in r.itemsMap)r.itemsMap.hasOwnProperty(e)&&!1===r.itemsMap[e]&&delete r.itemsMap[e];return{statusCode:200,body:r.body||r.itemsMap,contentType:r.contentType}}return{statusCode:404}})}))}put(e,t,r){return o(this,void 0,void 0,(function*(){const o=(0,u.pathsFromRoot)(e);return this._updateNodes(o,(function(e,o){try{for(let n=0,i=e.length;n0)break}else console.error("Cannot delete non-existing node "+o)}return t}))}flush(e){return this._getAllDescendentPaths(e).then(e=>this.getNodes(e)).then(e=>{for(const t in e){const r=e[t];r&&r.common&&r.local&&this._emitChange({path:r.path,origin:"local",oldValue:!1===r.local.body?void 0:r.local.body,newValue:!1===r.common.body?void 0:r.common.body}),e[t]=void 0}return this.setNodes(e)})}_emitChange(e){s.default.changeEvents[e.origin]&&this._emit("change",e)}fireInitial(){s.default.changeEvents.local&&this.forAllNodes(e=>{if((0,u.isDocument)(e.path)){const t=c(e);t&&this._emitChange({path:e.path,origin:"local",oldValue:void 0,oldContentType:void 0,newValue:t.body,newContentType:t.contentType})}}).then(()=>{this._emit("local-events-done")})}onDiff(e){this.diffHandler=e}migrate(e){return"object"!=typeof e||e.common||(e.common={},"string"==typeof e.path?"/"===e.path.substr(-1)&&"object"==typeof e.body&&(e.common.itemsMap=e.body):(e.local||(e.local={}),e.local.body=e.body,e.local.contentType=e.contentType)),e}_updateNodes(e,t){return new Promise((r,o)=>{this._doUpdateNodes(e,t,{resolve:r,reject:o})})}_doUpdateNodes(e,t,r){this._updateNodesRunning?this._updateNodesQueued.push({paths:e,cb:t,promise:r}):(this._updateNodesRunning=!0,this.getNodes(e).then(o=>{const n=(0,u.deepClone)(o),i=[];o=t(e,o);for(const e in o){const t=o[e];(0,u.equal)(t,n[e])?delete o[e]:(0,u.isDocument)(e)&&((0,u.equal)(t.local.body,t.local.previousBody)&&t.local.contentType===t.local.previousContentType||i.push({path:e,origin:"window",oldValue:t.local.previousBody,newValue:!1===t.local.body?void 0:t.local.body,oldContentType:t.local.previousContentType,newContentType:t.local.contentType}),delete t.local.previousBody,delete t.local.previousContentType)}this.setNodes(o).then(()=>{this._emitChangeEvents(i),r.resolve({statusCode:200})})}).then(()=>Promise.resolve(),e=>{r.reject(e)}).then(()=>{this._updateNodesRunning=!1;const e=this._updateNodesQueued.shift();e&&this._doUpdateNodes(e.paths,e.cb,e.promise)}))}_emitChangeEvents(e){for(let t=0,r=e.length;t{const r=[e],o=c(t[e]),n=Object.keys(o.itemsMap).map(t=>this._getAllDescendentPaths(e+t).then(e=>{for(let t=0,o=e.length;tr)}):Promise.resolve([e])}_getInternals(){return{getLatest:c,makeNode:l,isOutdated:h}}}(0,u.applyMixins)(f,[i.default]),e.exports=f},function(e,t,r){"use strict";e.exports=class{constructor(){this.reset()}static _rs_init(){}get scopes(){return Object.keys(this.scopeModeMap).map(e=>({name:e,mode:this.scopeModeMap[e]}))}get scopeParameter(){return this.scopes.map(e=>`${this._scopeNameForParameter(e)}:${e.mode}`).join(" ")}claim(e,t){if("string"!=typeof e||-1!==e.indexOf("/")||0===e.length)throw new Error("Scope should be a non-empty string without forward slashes");if(!t.match(/^rw?$/))throw new Error("Mode should be either 'r' or 'rw'");this._adjustRootPaths(e),this.scopeModeMap[e]=t}get(e){return this.scopeModeMap[e]}remove(e){const t={};for(const e in this.scopeModeMap)t[e]=this.scopeModeMap[e];this.reset(),delete t[e];for(const e in t)this.claim(e,t[e])}checkPermission(e,t){const r=this.get(e);return r&&("r"===t||"rw"===r)}checkPathPermission(e,t){if(this.checkPermission("*",t))return!0;const r=this._getModuleName(e);return!!this.checkPermission(r,t)}reset(){this.rootPaths=[],this.scopeModeMap={}}_getModuleName(e){if("/"!==e[0])throw new Error("Path should start with a slash");const t=e.replace(/^\/public/,"").match(/^\/([^/]*)\//);return t?t[1]:"*"}_adjustRootPaths(e){"*"in this.scopeModeMap||"*"===e?this.rootPaths=["/"]:e in this.scopeModeMap||(this.rootPaths.push("/"+e+"/"),this.rootPaths.push("/public/"+e+"/"))}_scopeNameForParameter(e){if("*"===e.name&&this.storageType){if("2012.04"===this.storageType)return"";if(this.storageType.match(/remotestorage-0[01]/))return"root"}return e.name}setStorageType(e){this.storageType=e}}},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=r(0),i=o(r(1));e.exports=class{constructor(){this.pendingActivations=[],this.reset()}set(e,t){if("string"!=typeof e)throw new Error("path should be a string");if(!(0,n.isFolder)(e))throw new Error("path should be a folder");if(!t.match(/^(FLUSH|SEEN|ALL)$/))throw new Error("strategy should be 'FLUSH', 'SEEN', or 'ALL'");this._rootPaths[e]=t,"ALL"===t&&(this.activateHandler?this.activateHandler(e):this.pendingActivations.push(e))}enable(e){this.set(e,"ALL")}disable(e){this.set(e,"FLUSH")}onActivate(e){(0,i.default)("[Caching] Setting activate handler",e,this.pendingActivations),this.activateHandler=e;for(let t=0;t=r-this.maxAge?t.v:void 0}set(e,t){this._items[e]={v:t,t:(new Date).getTime()}}}class y extends u.RemoteBase{constructor(e,t){if(super(e),this.online=!0,this.storageApi="draft-dejong-remotestorage-19",this.addEvents(["connected","not-connected"]),this.clientId=t,this._fileIdCache=new g(300),l=(0,s.localStorageAvailable)(),l){const e=(0,s.getJSONFromLocalStorage)(h);e&&this.configure(e)}}configure(e){void 0!==e.userAddress&&(this.userAddress=e.userAddress),void 0!==e.token&&(this.token=e.token);const t=function(){l&&localStorage.setItem(h,JSON.stringify({userAddress:this.userAddress,token:this.token}))},r=function(){this.connected=!1,delete this.token,l&&localStorage.removeItem(h)};this.token?(this.connected=!0,this.userAddress?(this._emit("connected"),t.apply(this)):this.info().then(e=>{this.userAddress=e.user.emailAddress,this._emit("connected"),t.apply(this)}).catch(()=>{r.apply(this),this.rs._emit("error",new Error("Could not fetch user info."))})):r.apply(this)}connect(){this.rs.setBackend("googledrive"),this.rs.authorize({authURL:"https://accounts.google.com/o/oauth2/auth",scope:"https://www.googleapis.com/auth/drive",clientId:this.clientId})}get(e,t={}){return(0,s.isFolder)(e)?this._getFolder(m(e)):this._getFile(m(e),t)}put(e,t,r,o={}){const n=m(e);function i(e){if(e.status>=200&&e.status<300){const t=JSON.parse(e.responseText),r=this.stripQuotes(t.etag);return Promise.resolve({statusCode:200,contentType:t.mimeType,revision:r})}return 412===e.status?Promise.resolve({statusCode:412,revision:"conflict"}):Promise.reject("PUT failed with status "+e.status+" ("+e.responseText+")")}return this._getFileId(n).then(e=>e?o&&"*"===o.ifNoneMatch?i({status:412}):this._updateFile(e,n,t,r,o).then(i):this._createFile(n,t,r).then(i))}delete(e,t={}){const r=m(e);return this._getFileId(r).then(e=>e?this._getMeta(e).then(r=>{let o;return"object"==typeof r&&"string"==typeof r.etag&&(o=this.stripQuotes(r.etag)),t&&t.ifMatch&&t.ifMatch!==o?{statusCode:412,revision:o}:this._request("DELETE",c+"/drive/v2/files/"+e,{}).then(e=>200===e.status||204===e.status?{statusCode:200}:Promise.reject("Delete failed: "+e.status+" ("+e.responseText+")"))}):Promise.resolve({statusCode:200}))}info(){return this._request("GET","https://www.googleapis.com/drive/v2/about?fields=user",{}).then((function(e){try{const t=JSON.parse(e.responseText);return Promise.resolve(t)}catch(e){return Promise.reject(e)}}))}_updateFile(e,t,r,o,n){const i={mimeType:o},s={"Content-Type":"application/json; charset=UTF-8"};return n&&n.ifMatch&&(s["If-Match"]=this.addQuotes(n.ifMatch)),this._request("PUT",c+"/upload/drive/v2/files/"+e+"?uploadType=resumable",{body:JSON.stringify(i),headers:s}).then(e=>412===e.status?e:this._request("PUT",e.getResponseHeader("Location"),{body:o.match(/^application\/json/)?JSON.stringify(r):r}))}_createFile(e,t,r){return this._getParentId(e).then(o=>{const n={title:d(p(e)),mimeType:r,parents:[{kind:"drive#fileLink",id:o}]};return this._request("POST",c+"/upload/drive/v2/files?uploadType=resumable",{body:JSON.stringify(n),headers:{"Content-Type":"application/json; charset=UTF-8"}}).then(e=>this._request("POST",e.getResponseHeader("Location"),{body:r.match(/^application\/json/)?JSON.stringify(t):t}))})}_getFile(e,t){return this._getFileId(e).then(e=>this._getMeta(e).then(e=>{let r;if("object"==typeof e&&"string"==typeof e.etag&&(r=this.stripQuotes(e.etag)),t&&t.ifNoneMatch&&r===t.ifNoneMatch)return Promise.resolve({statusCode:304});if(!e.downloadUrl){if(!e.exportLinks||!e.exportLinks["text/html"])return Promise.resolve({statusCode:200,body:"",contentType:e.mimeType,revision:r});e.mimeType+=";export=text/html",e.downloadUrl=e.exportLinks["text/html"]}return this._request("GET",e.downloadUrl,{responseType:"arraybuffer"}).then(t=>(0,s.getTextFromArrayBuffer)(t.response,"UTF-8").then((function(o){let n=o;if(e.mimeType.match(/^application\/json/))try{n=JSON.parse(n)}catch(e){}else(0,s.shouldBeTreatedAsBinary)(o,e.mimeType)&&(n=t.response);return{statusCode:200,body:n,contentType:e.mimeType,revision:r}})))}))}_getFolder(e){return this._getFileId(e).then(t=>{let r,o,n;if(!t)return Promise.resolve({statusCode:404});const i="'"+t+"' in parents";return this._request("GET",c+"/drive/v2/files?q="+encodeURIComponent(i)+"&fields="+encodeURIComponent("items(downloadUrl,etag,fileSize,id,mimeType,title,labels)")+"&maxResults=1000&trashed=false",{}).then(t=>{var i;if(200!==t.status)return Promise.reject("request failed or something: "+t.status);try{r=JSON.parse(t.responseText)}catch(e){return Promise.reject("non-JSON response from GoogleDrive")}n={};for(const t of r.items)(null===(i=t.labels)||void 0===i?void 0:i.trashed)||(o=this.stripQuotes(t.etag),"application/vnd.google-apps.folder"===t.mimeType?(this._fileIdCache.set(e+(0,s.cleanPath)(t.title)+"/",t.id),n[t.title+"/"]={ETag:o}):(this._fileIdCache.set(e+(0,s.cleanPath)(t.title),t.id),n[t.title]={ETag:o,"Content-Type":t.mimeType,"Content-Length":t.fileSize}));return Promise.resolve({statusCode:200,body:n,contentType:"application/json; charset=UTF-8",revision:void 0})})})}_getParentId(e){const t=f(e);return this._getFileId(t).then(e=>e?Promise.resolve(e):this._createFolder(t))}_createFolder(e){return this._getParentId(e).then(t=>this._request("POST",c+"/drive/v2/files",{body:JSON.stringify({title:d(p(e)),mimeType:"application/vnd.google-apps.folder",parents:[{id:t}]}),headers:{"Content-Type":"application/json; charset=UTF-8"}}).then(e=>{const t=JSON.parse(e.responseText);return Promise.resolve(t.id)}))}_getFileId(e){let t;return"/"===e?Promise.resolve("root"):(t=this._fileIdCache.get(e))?Promise.resolve(t):this._getFolder(f(e)).then(()=>(t=this._fileIdCache.get(e),t?Promise.resolve(t):"/"===e.substr(-1)?this._createFolder(e).then(()=>this._getFileId(e)):Promise.resolve()))}_getMeta(e){return this._request("GET",c+"/drive/v2/files/"+e,{}).then((function(t){return 200===t.status?Promise.resolve(JSON.parse(t.responseText)):Promise.reject("request (getting metadata for "+e+") failed with status: "+t.status)}))}_request(e,t,r){return this.isForbiddenRequestMethod(e,t)?Promise.reject(`Don't use ${e} on directories!`):(r.headers||(r.headers={}),r.headers.Authorization="Bearer "+this.token,this.rs._emit("wire-busy",{method:e,isFolder:(0,s.isFolder)(t)}),(0,a.requestWithTimeout)(e,t,r).then(r=>r&&401===r.status?void this.connect():(this.online||(this.online=!0,this.rs._emit("network-online")),this.rs._emit("wire-done",{method:e,isFolder:(0,s.isFolder)(t),success:!0}),Promise.resolve(r)),r=>(this.online&&(this.online=!1,this.rs._emit("network-offline")),this.rs._emit("wire-done",{method:e,isFolder:(0,s.isFolder)(t),success:!1}),Promise.reject(r))))}static _rs_init(e){const t=e.apiKeys.googledrive;var r;t&&(e.googledrive=new y(e,t.clientId),"googledrive"===e.backend&&(e._origRemote=e.remote,e.remote=e.googledrive,(r=e)._origBaseClientGetItemURL||(r._origBaseClientGetItemURL=n.default.prototype.getItemURL,n.default.prototype.getItemURL=function(){throw new Error("getItemURL is not implemented for Google Drive yet")})))}static _rs_supported(){return!0}static _rs_cleanup(e){var t;e.setBackend(void 0),e._origRemote&&(e.remote=e._origRemote,delete e._origRemote),(t=e)._origBaseClientGetItemURL&&(n.default.prototype.getItemURL=t._origBaseClientGetItemURL,delete t._origBaseClientGetItemURL)}}(0,s.applyMixins)(y,[i.default]),e.exports=y},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(2)),s=n(r(8)),a=n(r(27)),u=n(r(10)),c=n(r(5)),h=r(0),l=r(7),d=r(9),f=n(r(4));let p;const m="remotestorage:dropbox",g="https://api.dropboxapi.com/2/files/list_folder",y="https://api.dropboxapi.com/2/files/list_folder/continue";function v(e){return("/remotestorage/"+e).replace(/\/+$/,"").replace(/\/+/g,"/")}const _=/[\u007f-\uffff]/g;function b(e){return JSON.stringify(e).replace(_,(function(e){return"\\u"+("000"+e.charCodeAt(0).toString(16)).slice(-4)}))}function w(e,t){return new RegExp("^"+t.join("\\/")+"(\\/|$)").test(e.error_summary)}function P(e){return e instanceof ArrayBuffer||(0,l.isArrayBufferView)(e)}class E extends d.RemoteBase{constructor(e){if(super(e),this.online=!0,this.storageApi="draft-dejong-remotestorage-19",this._initialFetchDone=!1,this.addEvents(["connected","not-connected"]),this.clientId=e.apiKeys.dropbox.appKey,this.TOKEN_URL="https://api.dropboxapi.com/oauth2/token",this._revCache=new a.default("rev"),this._fetchDeltaCursor=null,this._fetchDeltaPromise=null,this._itemRefs={},p=(0,h.localStorageAvailable)(),p){const e=(0,h.getJSONFromLocalStorage)(m);e&&this.configure(e),this._itemRefs=(0,h.getJSONFromLocalStorage)(m+":shares")||{}}this.connected&&setTimeout(this._emit.bind(this),0,"connected")}connect(){return o(this,void 0,void 0,(function*(){try{if(this.rs.setBackend("dropbox"),this.token)R(this.rs);else{const{codeVerifier:e,codeChallenge:t,state:r}=yield(0,h.generateCodeVerifier)();sessionStorage.setItem("remotestorage:codeVerifier",e),sessionStorage.setItem("remotestorage:state",r),this.rs.authorize({authURL:"https://www.dropbox.com/oauth2/authorize",scope:"account_info.read files.content.read files.content.write files.metadata.read files.metadata.write",clientId:this.clientId,response_type:"code",state:r,code_challenge:t,code_challenge_method:"S256",token_access_type:"offline"})}}catch(e){throw this.rs._emit("error",e),this.rs.setBackend(void 0),e}}))}configure(e){return o(this,void 0,void 0,(function*(){void 0!==e.userAddress&&(this.userAddress=e.userAddress),void 0!==e.token&&(this.token=e.token),void 0!==e.refreshToken&&(this.refreshToken=e.refreshToken),void 0!==e.tokenType&&(this.tokenType=e.tokenType);const t=()=>{p&&localStorage.setItem(m,JSON.stringify({userAddress:this.userAddress,token:this.token,refreshToken:this.refreshToken,tokenType:this.tokenType}))},r=()=>{this.connected=!1,p&&localStorage.removeItem(m),this.rs.setBackend(void 0)};if(this.refreshToken||this.token)if(this.connected=!0,this.userAddress)this._emit("connected"),t();else try{const e=yield this.info();this.userAddress=e.email,this._emit("connected"),t()}catch(e){this.connected=!1,this.rs._emit("error",new Error("Could not fetch user info.")),t.apply(this)}else r()}))}_getFolder(e){const t=this._revCache,r=r=>{let n;if(200!==r.status&&409!==r.status)return Promise.reject("Unexpected response status: "+r.status);try{n=JSON.parse(r.responseText)}catch(e){return Promise.reject(e)}if(409===r.status)return w(n,["path","not_found"])?Promise.resolve({}):Promise.reject(new Error("API returned an error: "+n.error_summary));const i=n.entries.reduce((r,o)=>{try{const n="folder"===o[".tag"],i=o.path_display.split("/").slice(-1)[0]+(n?"/":"");if(n)r[i]={ETag:t.get(e+i)};else{const t=new Date(o.server_modified);r[i]={ETag:o.rev,"Content-Length":o.size,"Last-Modified":t.toUTCString()},this._revCache.set(e+i,o.rev)}}catch(t){console.error(`[Dropbox] folder “${e}” has entry ${JSON.stringify(o)}:`,t)}return r},{});return n.has_more?o(n.cursor).then((function(e){return Object.assign(i,e)})):Promise.resolve(i)},o=e=>{const t={body:{cursor:e}};return this._request("POST",y,t).then(r)};return this._request("POST",g,{body:{path:v(e)}}).then(r).then((function(r){return Promise.resolve({statusCode:200,body:r,contentType:"application/json; charset=UTF-8",revision:t.get(e)})}))}get(e,t={}){if(!this.connected)return Promise.reject("not connected (path: "+e+")");const r=this._revCache.get(e);if(null===r)return Promise.resolve({statusCode:404});if(t&&t.ifNoneMatch){if(!this._initialFetchDone)return this.fetchDelta().then(()=>this.get(e,t));if(r&&r===t.ifNoneMatch)return Promise.resolve({statusCode:304})}if("/"===e.slice(-1))return this._getFolder(e);const o={headers:{"Dropbox-API-Arg":b({path:v(e)})},responseType:"arraybuffer"};return t&&t.ifNoneMatch&&(o.headers["If-None-Match"]=t.ifNoneMatch),this._request("GET","https://content.dropboxapi.com/2/files/download",o).then(t=>{const r=t.status;let o,n,i,s;return 200!==r&&409!==r?Promise.resolve({statusCode:r}):(o=t.getResponseHeader("Dropbox-API-Result"),(0,h.getTextFromArrayBuffer)(t.response,"UTF-8").then(a=>{n=a,409===r&&(o=n);try{o=JSON.parse(o)}catch(e){return Promise.reject(e)}if(409===r)return w(o,["path","not_found"])?{statusCode:404}:Promise.reject(new Error('API error while downloading file ("'+e+'"): '+o.error_summary));if(i=t.getResponseHeader("Content-Type"),s=o.rev,this._revCache.set(e,s),this._shareIfNeeded(e),(0,h.shouldBeTreatedAsBinary)(a,i))n=t.response;else try{n=JSON.parse(n),i="application/json; charset=UTF-8"}catch(e){}return{statusCode:r,body:n,contentType:i,revision:s}}))})}put(e,t,r,n={}){return o(this,void 0,void 0,(function*(){if(!this.connected)throw new Error("not connected (path: "+e+")");const o=this._revCache.get(e);if(n&&n.ifMatch&&o&&o!==n.ifMatch)return{statusCode:412,revision:o};if(n&&"*"===n.ifNoneMatch&&o&&"rev"!==o)return{statusCode:412,revision:o};if(!r.match(/charset=/)&&P(t)&&(r+="; charset=binary"),t.length>157286400)throw new Error("Cannot upload file larger than 150MB");const i=n&&(n.ifMatch||"*"===n.ifNoneMatch),s={body:t,contentType:r,path:e};if(i){const t=yield this._getMetadata(e);if(n&&"*"===n.ifNoneMatch&&t)return{statusCode:412,revision:t.rev};if(n&&n.ifMatch&&t&&t.rev!==n.ifMatch)return{statusCode:412,revision:t.rev}}const a=yield this._uploadSimple(s);return this._shareIfNeeded(e),a}))}delete(e,t={}){return o(this,void 0,void 0,(function*(){if(!this.connected)throw new Error("not connected (path: "+e+")");const r=this._revCache.get(e);if((null==t?void 0:t.ifMatch)&&r&&t.ifMatch!==r)return{statusCode:412,revision:r};if(null==t?void 0:t.ifMatch){const r=yield this._getMetadata(e);if((null==t?void 0:t.ifMatch)&&r&&r.rev!==t.ifMatch)return{statusCode:412,revision:r.rev}}return this._deleteSimple(e)}))}_shareIfNeeded(e){if(e.match(/^\/public\/.*[^/]$/)&&void 0===this._itemRefs[e])return this.share(e)}share(e){const t={body:{path:v(e)}};return this._request("POST","https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings",t).then(t=>{if(200!==t.status&&409!==t.status)return Promise.reject(new Error("Invalid response status:"+t.status));let r;try{r=JSON.parse(t.responseText)}catch(e){return Promise.reject(new Error("Invalid response body: "+t.responseText))}return 409===t.status?w(r,["shared_link_already_exists"])?this._getSharedLink(e):Promise.reject(new Error("API error: "+r.error_summary)):Promise.resolve(r.url)}).then(t=>(this._itemRefs[e]=t,p&&localStorage.setItem(m+":shares",JSON.stringify(this._itemRefs)),Promise.resolve(t)),t=>(t.message='Sharing Dropbox file or folder ("'+e+'") failed: '+t.message,Promise.reject(t)))}info(){return this._request("POST","https://api.dropboxapi.com/2/users/get_current_account",{}).then((function(e){let t;try{const r=JSON.parse(e.responseText);t=null==r?void 0:r.email}catch(t){return Promise.reject(new Error("Could not query current account info: Invalid API response: "+e.responseText))}return Promise.resolve({email:t})}))}_request(e,t,r,n=1){return o(this,void 0,void 0,(function*(){if(this.isForbiddenRequestMethod(e,t))throw`Don't use ${e} on directories!`;if(!this.token)throw new c.default("No access token");r.headers||(r.headers={}),r.headers.Authorization="Bearer "+this.token,"object"!=typeof r.body||P(r.body)||(r.body=JSON.stringify(r.body),r.headers["Content-Type"]="application/json; charset=UTF-8"),this.rs._emit("wire-busy",{method:e,isFolder:(0,h.isFolder)(t)});try{const o=yield(0,l.requestWithTimeout)(e,t,r);return this.online||(this.online=!0,this.rs._emit("network-online")),this.rs._emit("wire-done",{method:e,isFolder:(0,h.isFolder)(t),success:!0}),401===(null==o?void 0:o.status)&&this.refreshToken?n>=3?(console.error(`Abandoned after ${n} attempts: ${e} ${t}`),o):(this.rs._emit("wire-busy",{method:e,isFolder:(0,h.isFolder)(t)}),yield f.default.refreshAccessToken(this.rs,this,this.refreshToken),this.rs._emit("wire-done",{method:e,isFolder:(0,h.isFolder)(t),success:!0}),this._request(e,t,r,n+1)):[503,429].includes(null==o?void 0:o.status)?(this.online&&(this.online=!1,this.rs._emit("network-offline")),n>=3?(console.warn(`Abandoned after ${n} attempts: ${e} ${t}`),o):(yield new Promise(e=>setTimeout(e,(0,l.retryAfterMs)(o))),this._request(e,t,r,n+1))):o}catch(r){throw this.online&&(this.online=!1,this.rs._emit("network-offline")),this.rs._emit("wire-done",{method:e,isFolder:(0,h.isFolder)(t),success:!1}),r}}))}fetchDelta(...e){if(this._fetchDeltaPromise)return this._fetchDeltaPromise;const t=e=>o(this,void 0,void 0,(function*(){let r,o;"string"==typeof e?(r=y,o={cursor:e}):(r=g,o={path:"/remotestorage",recursive:!0,include_deleted:!0});try{const n=yield this._request("POST",r,{body:o});if(401===n.status)throw new c.default;if(200!==n.status&&409!==n.status)throw new Error("Invalid response status: "+n.status);let i;try{i=JSON.parse(n.responseText)}catch(e){throw new Error("Invalid response body: "+n.responseText)}if(409===n.status){if(!w(i,["path","not_found"]))throw new Error("API returned an error: "+i.error_summary);i={cursor:null,entries:[],has_more:!1}}if(e||this._revCache.deactivatePropagation(),i.entries.forEach(e=>{const t=e.path_display.slice("/remotestorage".length);"deleted"===e[".tag"]?(this._revCache.delete(t),this._revCache.delete(t+"/")):"file"===e[".tag"]&&this._revCache.set(t,e.rev)}),this._fetchDeltaCursor=i.cursor,i.has_more)return t(i.cursor);this._revCache.activatePropagation(),this._initialFetchDone=!0}catch(e){if("timeout"===e)return;throw e}}));return this._fetchDeltaPromise=t(this._fetchDeltaCursor).catch(e=>("object"==typeof e&&"message"in e?e.message="Dropbox: fetchDelta: "+e.message:e="Dropbox: fetchDelta: "+e,this.rs._emit("error",e),this._fetchDeltaPromise=null,Promise.reject(e))).then(()=>(this._fetchDeltaPromise=null,Promise.resolve(e))),this._fetchDeltaPromise}_getMetadata(e){const t={path:v(e)};return this._request("POST","https://api.dropboxapi.com/2/files/get_metadata",{body:t}).then(e=>{if(200!==e.status&&409!==e.status)return Promise.reject(new Error("Invalid response status:"+e.status));let t;try{t=JSON.parse(e.responseText)}catch(t){return Promise.reject(new Error("Invalid response body: "+e.responseText))}return 409===e.status?w(t,["path","not_found"])?Promise.resolve():Promise.reject(new Error("API error: "+t.error_summary)):Promise.resolve(t)}).then(void 0,t=>(t.message='Could not load metadata for file or folder ("'+e+'"): '+t.message,Promise.reject(t)))}_uploadSimple(e){const t={path:v(e.path),mode:{".tag":"overwrite",update:void 0},mute:!0};return e.ifMatch&&(t.mode={".tag":"update",update:e.ifMatch}),this._request("POST","https://content.dropboxapi.com/2/files/upload",{body:e.body,headers:{"Content-Type":"application/octet-stream","Dropbox-API-Arg":b(t)}}).then(t=>{if(200!==t.status&&409!==t.status)return Promise.resolve({statusCode:t.status});let r;try{r=JSON.parse(t.responseText)}catch(e){return Promise.reject(new Error("Invalid API result: "+t.responseText))}return 409===t.status?w(r,["path","conflict"])?this._getMetadata(e.path).then((function(e){return Promise.resolve({statusCode:412,revision:e.rev})})):(this.rs._emit("error",new Error(r.error_summary)),Promise.resolve({statusCode:t.status})):(this._revCache.set(e.path,r.rev),Promise.resolve({statusCode:t.status,revision:r.rev}))})}_deleteSimple(e){const t={path:v(e)};return this._request("POST","https://api.dropboxapi.com/2/files/delete",{body:t}).then(e=>{if(200!==e.status&&409!==e.status)return Promise.resolve({statusCode:e.status});let t;try{t=JSON.parse(e.responseText)}catch(t){return Promise.reject(new Error("Invalid response body: "+e.responseText))}if(409===e.status){if(w(t,["path_lookup","not_found"]))return Promise.resolve({statusCode:404});this.rs._emit("error",new Error(t.error_summary))}return Promise.resolve({statusCode:e.status})}).then(t=>(200!==t.statusCode&&404!==t.statusCode||(this._revCache.delete(e),delete this._itemRefs[e]),Promise.resolve(t)),t=>(t.message='Could not delete Dropbox file or folder ("'+e+'"): '+t.message,Promise.reject(t)))}_getSharedLink(e){return o(this,void 0,void 0,(function*(){const t={body:{path:v(e),direct_only:!0}};return this._request("POST","https://api.dropbox.com/2/sharing/list_shared_links",t).then(e=>{if(200!==e.status&&409!==e.status)return Promise.reject(new Error("Invalid response status: "+e.status));let t;try{t=JSON.parse(e.responseText)}catch(t){return Promise.reject(new Error("Invalid response body: "+e.responseText))}return 409===e.status?Promise.reject(new Error("API error: "+(null==t?void 0:t.error_summary)||!1)):t.links.length?Promise.resolve(t.links[0].url):Promise.reject(new Error("No links returned"))},t=>(t.message='Could not get link to a shared file or folder ("'+e+'"): '+t.message,Promise.reject(t)))}))}static _rs_init(e){p=(0,h.localStorageAvailable)(),e.apiKeys.dropbox&&(e.dropbox=new E(e)),"dropbox"===e.backend&&R(e)}static _rs_supported(){return!0}static _rs_cleanup(e){!function(e){(function(e){e._origRemote&&(e.remote=e._origRemote,delete e._origRemote)})(e),function(e){if(!e._dropboxOrigSync)return;e.sync.sync=e._dropboxOrigSync,delete e._dropboxOrigSync}(e),function(e){if(!e._origBaseClientGetItemURL)return;s.default.prototype.getItemURL=e._origBaseClientGetItemURL,delete e._origBaseClientGetItemURL}(e),A(e)}(e),p&&localStorage.removeItem(m),e.setBackend(void 0)}}function T(e,...t){e._dropboxOrigSync||(e._dropboxOrigSync=e.sync.sync.bind(e.sync),e.sync.sync=function(){return this.dropbox.fetchDelta(e,...t).then(e._dropboxOrigSync,(function(t){e._emit("error",new u.default(t)),e._emit("sync-done")}))}.bind(e))}function A(e){e._dropboxOrigSyncCycle&&(e.syncCycle=e._dropboxOrigSyncCycle,delete e._dropboxOrigSyncCycle)}function R(e){!function(e){e._origRemote||(e._origRemote=e.remote,e.remote=e.dropbox)}(e),e.sync?T(e):function(e,...t){e._dropboxOrigSyncCycle||(e._dropboxOrigSyncCycle=e.syncCycle,e.syncCycle=()=>{if(!e.sync)throw new Error("expected sync to be initialized by now");T(e),e._dropboxOrigSyncCycle(e,...t),A(e)})}(e),function(e){e._origBaseClientGetItemURL||(e._origBaseClientGetItemURL=s.default.prototype.getItemURL,s.default.prototype.getItemURL=function(){throw new Error("getItemURL is not implemented for Dropbox yet")})}(e)}(0,h.applyMixins)(E,[i.default]),e.exports=E},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=o(r(28)),i=o(r(1)),s=r(0);let a,u;let c={};const h=function(e){return new Promise((t,r)=>{if(e in c)return t(c[e]);return new n.default({tls_only:!1,uri_fallback:!0,request_timeout:5e3}).lookup(e,(function(o,n){if(o)return r(o);if("object"!=typeof n.idx.links.remotestorage||"number"!=typeof n.idx.links.remotestorage.length||n.idx.links.remotestorage.length<=0)return(0,i.default)("[Discover] WebFinger record for "+e+" does not have remotestorage defined in the links section ",JSON.stringify(n.json)),r("WebFinger record for "+e+" does not have remotestorage defined in the links section.");const s=n.idx.links.remotestorage[0],a=s.properties["http://tools.ietf.org/html/rfc6749#section-4.2"]||s.properties["auth-endpoint"],h=s.properties["http://remotestorage.io/spec/version"]||s.type;return c[e]={href:s.href,storageApi:h,authURL:a,properties:s.properties},u&&(localStorage["remotestorage:discover"]=JSON.stringify({cache:c})),t(c[e])}))})};(h.DiscoveryError=function(e){this.name="DiscoveryError",this.message=e,this.stack=(new Error).stack}).prototype=Object.create(Error.prototype),h.DiscoveryError.prototype.constructor=h.DiscoveryError,h._rs_init=function(){if(u=(0,s.localStorageAvailable)(),u)try{const e=JSON.parse(localStorage["remotestorage:discover"]);c=e.cache}catch(e){}},h._rs_supported=function(){return a=Object.prototype.hasOwnProperty.call(s.globalContext,"XMLHttpRequest"),a},h._rs_cleanup=function(){u&&delete localStorage["remotestorage:discover"]},e.exports=h},function(e,t,r){"use strict";const o=(this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(r(2)),n=r(0);class i{constructor(){this.addEvents(["background","foreground"]),this.mode="undefined"!=typeof window?"browser":"node","browser"===this.mode&&(this.setBrowserPrefixedNames(),document.addEventListener(this.visibilityChangeEvent,this.setVisibility.bind(this),!1),this.setVisibility())}setBrowserPrefixedNames(){"browser"===this.mode&&(void 0!==document.hidden?(this.hiddenProperty="hidden",this.visibilityChangeEvent="visibilitychange"):void 0!==document.mozHidden?(this.hiddenProperty="mozHidden",this.visibilityChangeEvent="mozvisibilitychange"):void 0!==document.msHidden?(this.hiddenProperty="msHidden",this.visibilityChangeEvent="msvisibilitychange"):void 0!==document.webkitHidden&&(this.hiddenProperty="webkitHidden",this.visibilityChangeEvent="webkitvisibilitychange"))}setVisibility(){document[this.hiddenProperty]?this.goBackground():this.goForeground()}isBrowser(){return"browser"===this.mode}isNode(){return"node"===this.mode}goBackground(){this._emit("background")}goForeground(){this._emit("foreground")}static _rs_init(){}static _rs_cleanup(){}}(0,n.applyMixins)(i,[o.default]),e.exports=i},function(e,t,r){e.exports=r(19)},function(e,t,r){"use strict";var o=this&&this.__createBinding||(Object.create?function(e,t,r,o){void 0===o&&(o=r);var n=Object.getOwnPropertyDescriptor(t,r);n&&!("get"in n?!t.__esModule:n.writable||n.configurable)||(n={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,o,n)}:function(e,t,r,o){void 0===o&&(o=r),e[o]=t[r]}),n=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&o(t,e,r);return n(t,e),t},s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const a=s(r(3)),u=s(r(1)),c=r(0),h=s(r(12)),l=s(r(4)),d=s(r(8)),f=s(r(13)),p=s(r(2)),m=s(r(14)),g=s(r(15)),y=s(r(16)),v=s(r(10)),_=s(r(5)),b=s(r(30)),w=i(r(0)),P=(0,c.getGlobalContext)();let E;function T(e){return 403!==e.statusCode&&401!==e.statusCode||this._emit("error",new _.default),Promise.resolve(e)}function A(e){return"number"==typeof e&&e>=2e3&&e<=36e5}class R{constructor(e){this._pending=[],this._cleanups=[],this._pathHandlers={change:{}},this.apiKeys={},this._init=b.default.loadFeatures,this.features=b.default.features,this.loadFeature=b.default.loadFeature,this.featureSupported=b.default.featureSupported,this.featureDone=b.default.featureDone,this.featuresDone=b.default.featuresDone,this.featuresLoaded=b.default.featuresLoaded,this.featureInitialized=b.default.featureInitialized,this.featureFailed=b.default.featureFailed,this.hasFeature=b.default.hasFeature,this._setCachingModule=b.default._setCachingModule,this._collectCleanupFunctions=b.default._collectCleanupFunctions,this._fireReady=b.default._fireReady,this.initFeature=b.default.initFeature,"object"==typeof e&&(0,c.extend)(a.default,e),this.addEvents(["ready","authing","connecting","connected","disconnected","not-connected","conflict","error","features-loaded","sync-interval-change","sync-req-done","sync-done","wire-busy","wire-done","network-offline","network-online"]),this._setGPD({get:this._pendingGPD("get"),put:this._pendingGPD("put"),delete:this._pendingGPD("delete")}),E=(0,c.localStorageAvailable)(),E&&(this.apiKeys=(0,c.getJSONFromLocalStorage)("remotestorage:api-keys")||{},this.setBackend(localStorage.getItem("remotestorage:backend")||"remotestorage"));const t=this.on;this.on=function(e,r){if(this._allLoaded)switch(e){case"features-loaded":setTimeout(r,0);break;case"ready":this.remote&&setTimeout(r,0);break;case"connected":this.remote&&this.remote.connected&&setTimeout(r,0);break;case"not-connected":this.remote&&!this.remote.connected&&setTimeout(r,0)}return t.call(this,e,r)},this._init(),this.fireInitial=function(){this.local&&setTimeout(this.local.fireInitial.bind(this.local),0)}.bind(this),this.on("ready",this.fireInitial.bind(this)),this.loadModules()}get connected(){return this.remote.connected}loadModules(){a.default.modules.forEach(this.addModule.bind(this))}authorize(e){if(this.access.setStorageType(this.remote.storageApi),void 0===e.scope&&(e.scope=this.access.scopeParameter),P.cordova)e.redirectUri=a.default.cordovaRedirectUri;else{const t=l.default.getLocation();let r=t.origin;"/"!==t.pathname&&(r+=t.pathname),e.redirectUri=r}void 0===e.clientId&&(e.clientId=e.redirectUri.match(/^(https?:\/\/[^/]+)/)[0]),l.default.authorize(this,e)}impliedauth(e,t){e=e||this.remote.storageApi,t=t||String(document.location),(0,u.default)("ImpliedAuth proceeding due to absent authURL; storageApi = "+e+" redirectUri = "+t),this.remote.configure({token:l.default.IMPLIED_FAKE_TOKEN}),document.location.href=t}connect(e,t){if(this.setBackend("remotestorage"),e.indexOf("@")<0&&!e.match(/^(https?:\/\/)?[^\s\/$\.?#]+\.[^\s]*$/))return void this._emit("error",new R.DiscoveryError("Not a valid user address or URL."));if(e.indexOf("@")<0&&!e.match(/^https?:\/\//)&&(e="https://"+e),P.cordova){if("string"!=typeof a.default.cordovaRedirectUri)return void this._emit("error",new R.DiscoveryError("Please supply a custom HTTPS redirect URI for your Cordova app"));if(!P.cordova.InAppBrowser)return void this._emit("error",new R.DiscoveryError("Please include the InAppBrowser Cordova plugin to enable OAuth"))}this.remote.configure({userAddress:e}),this._emit("connecting");const r=setTimeout(()=>{this._emit("error",new R.DiscoveryError("No storage information found for this user address."))},a.default.discoveryTimeout);(0,y.default)(e).then(o=>{if(clearTimeout(r),this._emit("authing"),o.userAddress=e,this.remote.configure(o),!this.remote.connected)if(o.authURL)if(void 0===t)this.authorize({authURL:o.authURL});else{if("string"!=typeof t)throw new Error("Supplied bearer token must be a string");(0,u.default)("Skipping authorization sequence and connecting with known token"),this.remote.configure({token:t})}else this.impliedauth()},()=>{clearTimeout(r),this._emit("error",new R.DiscoveryError("No storage information found for this user address."))})}reconnect(){this.remote.configure({token:null}),"remotestorage"===this.backend?this.connect(this.remote.userAddress):this.remote.connect()}disconnect(){this.remote&&this.remote.configure({userAddress:null,href:null,storageApi:null,token:null,properties:null}),this._setGPD({get:this._pendingGPD("get"),put:this._pendingGPD("put"),delete:this._pendingGPD("delete")});const e=this._cleanups.length;let t=0;const r=()=>{t++,t>=e&&(this._init(),this._emit("disconnected"))};e>0?this._cleanups.forEach(e=>{const t=e(this);"object"==typeof t&&"function"==typeof t.then?t.then(r):r()}):r()}setBackend(e){this.backend=e,E&&(e?localStorage.setItem("remotestorage:backend",e):localStorage.removeItem("remotestorage:backend"))}onChange(e,t){this._pathHandlers.change[e]||(this._pathHandlers.change[e]=[]),this._pathHandlers.change[e].push(t)}enableLog(){a.default.logging=!0}disableLog(){a.default.logging=!1}log(...e){u.default.apply(R,e)}setApiKeys(e){const t=[S.GOOGLE,S.DROPBOX];if("object"!=typeof e||!Object.keys(e).every(e=>t.includes(e)))return console.error("setApiKeys() was called with invalid arguments"),!1;Object.keys(e).forEach(t=>{const r=e[t];if(r){switch(t){case S.DROPBOX:this.apiKeys[S.DROPBOX]={appKey:r},void 0!==this.dropbox&&this.dropbox.clientId===r||g.default._rs_init(this);break;case S.GOOGLE:this.apiKeys[S.GOOGLE]={clientId:r},void 0!==this.googledrive&&this.googledrive.clientId===r||m.default._rs_init(this)}return!0}delete this.apiKeys[t]}),E&&localStorage.setItem("remotestorage:api-keys",JSON.stringify(this.apiKeys))}setCordovaRedirectUri(e){if("string"!=typeof e||!e.match(/http(s)?:\/\//))throw new Error("Cordova redirect URI must be a URI string");a.default.cordovaRedirectUri=e}_setGPD(e,t){function r(e){return function(...r){return e.apply(t,r).then(T.bind(this))}}this.get=r(e.get),this.put=r(e.put),this.delete=r(e.delete)}_pendingGPD(e){return(...t)=>{const r=Array.prototype.slice.call(t);return new Promise((t,o)=>{this._pending.push({method:e,args:r,promise:{resolve:t,reject:o}})})}}_processPending(){this._pending.forEach(e=>{try{this[e.method](...e.args).then(e.promise.resolve,e.promise.reject)}catch(t){e.promise.reject(t)}}),this._pending=[]}_bindChange(e){e.on("change",this._dispatchEvent.bind(this,"change"))}_dispatchEvent(e,t){Object.keys(this._pathHandlers[e]).forEach(r=>{const o=r.length;t.path.substr(0,o)===r&&this._pathHandlers[e][r].forEach(e=>{const o={};for(const e in t)o[e]=t[e];o.relativePath=t.path.replace(new RegExp("^"+r),"");try{e(o)}catch(e){console.error("'change' handler failed: ",e,e.stack),this._emit("error",e)}})})}scope(e){if("string"!=typeof e)throw"Argument 'path' of baseClient.scope must be a string";return this.access.checkPathPermission(e,"r")||console.warn("WARNING: Please use remoteStorage.access.claim() to ask for access permissions first: https://remotestoragejs.readthedocs.io/en/latest/js-api/access.html#claim"),new d.default(this,e)}getSyncInterval(){return a.default.syncInterval}setSyncInterval(e){if(!A(e))throw e+" is not a valid sync interval";const t=a.default.syncInterval;a.default.syncInterval=e,this._emit("sync-interval-change",{oldValue:t,newValue:e})}getBackgroundSyncInterval(){return a.default.backgroundSyncInterval}setBackgroundSyncInterval(e){if(!A(e))throw e+" is not a valid sync interval";const t=a.default.backgroundSyncInterval;a.default.backgroundSyncInterval=e,this._emit("sync-interval-change",{oldValue:t,newValue:e})}getCurrentSyncInterval(){return a.default.isBackground?a.default.backgroundSyncInterval:a.default.syncInterval}getRequestTimeout(){return a.default.requestTimeout}setRequestTimeout(e){if("number"!=typeof e)throw e+" is not a valid request timeout";a.default.requestTimeout=e}syncCycle(){this.sync&&!this.sync.stopped&&(this.on("sync-done",()=>{this.sync&&!this.sync.stopped&&(this._syncTimer&&(clearTimeout(this._syncTimer),this._syncTimer=void 0),this._syncTimer=setTimeout(this.sync.sync.bind(this.sync),this.getCurrentSyncInterval()))}),this.sync.sync())}startSync(){return a.default.cache?(this.sync.stopped=!1,this.syncStopped=!1,this.sync.sync()):(console.warn("Nothing to sync, because caching is disabled."),Promise.resolve())}stopSync(){clearTimeout(this._syncTimer),this._syncTimer=void 0,this.sync?this.sync.stopped=!0:this.syncStopped=!0}addModule(e){const t=e.name,r=e.builder;if(Object.defineProperty(this,t,{configurable:!0,get:function(){const e=this._loadModule(t,r);return Object.defineProperty(this,t,{value:e}),e}}),-1!==t.indexOf("-")){const e=t.replace(/\-[a-z]/g,(function(e){return e[1].toUpperCase()}));Object.defineProperty(this,e,{get:function(){return this[t]}})}}_loadModule(e,t){if(t){return t(new d.default(this,"/"+e+"/"),new d.default(this,"/public/"+e+"/")).exports}throw"Unknown module: "+e}}var S;R.Authorize=l.default,R.SyncError=v.default,R.Unauthorized=_.default,R.DiscoveryError=y.default.DiscoveryError,R.util=w,Object.defineProperty(R.prototype,"access",{get:function(){const e=new h.default;return Object.defineProperty(this,"access",{value:e}),e},configurable:!0}),Object.defineProperty(R.prototype,"caching",{configurable:!0,get:function(){const e=new f.default;return Object.defineProperty(this,"caching",{value:e}),e}}),(0,c.applyMixins)(R,[p.default]),function(e){e.GOOGLE="googledrive",e.DROPBOX="dropbox"}(S||(S={})),e.exports=R},function(e,t,r){"use strict";(function(e){ -/*! +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define("RemoteStorage", [], factory); + else if(typeof exports === 'object') + exports["RemoteStorage"] = factory(); + else + root["RemoteStorage"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 0); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "./node_modules/base64-js/index.js": +/*!*****************************************!*\ + !*** ./node_modules/base64-js/index.js ***! + \*****************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.byteLength = byteLength +exports.toByteArray = toByteArray +exports.fromByteArray = fromByteArray + +var lookup = [] +var revLookup = [] +var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array + +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] + revLookup[code.charCodeAt(i)] = i +} + +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup['-'.charCodeAt(0)] = 62 +revLookup['_'.charCodeAt(0)] = 63 + +function getLens (b64) { + var len = b64.length + + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen + + var i + for (i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) + } + + return parts.join('') +} + + +/***/ }), + +/***/ "./node_modules/buffer/index.js": +/*!**************************************!*\ + !*** ./node_modules/buffer/index.js ***! + \**************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) {/*! * The buffer module from node.js, for the browser. * * @author Feross Aboukhadijeh * @license MIT */ -var o=r(21),n=r(22),i=r(23);function s(){return u.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function a(e,t){if(s()=s())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+s().toString(16)+" bytes");return 0|e}function p(e,t){if(u.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var r=e.length;if(0===r)return 0;for(var o=!1;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":case void 0:return B(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return q(e).length;default:if(o)return B(e).length;t=(""+t).toLowerCase(),o=!0}}function m(e,t,r){var o=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return M(this,t,r);case"utf8":case"utf-8":return R(this,t,r);case"ascii":return S(this,t,r);case"latin1":case"binary":return k(this,t,r);case"base64":return A(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return O(this,t,r);default:if(o)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),o=!0}}function g(e,t,r){var o=e[t];e[t]=e[r],e[r]=o}function y(e,t,r,o,n){if(0===e.length)return-1;if("string"==typeof r?(o=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,isNaN(r)&&(r=n?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(n)return-1;r=e.length-1}else if(r<0){if(!n)return-1;r=0}if("string"==typeof t&&(t=u.from(t,o)),u.isBuffer(t))return 0===t.length?-1:v(e,t,r,o,n);if("number"==typeof t)return t&=255,u.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?n?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):v(e,[t],r,o,n);throw new TypeError("val must be string, number or Buffer")}function v(e,t,r,o,n){var i,s=1,a=e.length,u=t.length;if(void 0!==o&&("ucs2"===(o=String(o).toLowerCase())||"ucs-2"===o||"utf16le"===o||"utf-16le"===o)){if(e.length<2||t.length<2)return-1;s=2,a/=2,u/=2,r/=2}function c(e,t){return 1===s?e[t]:e.readUInt16BE(t*s)}if(n){var h=-1;for(i=r;ia&&(r=a-u),i=r;i>=0;i--){for(var l=!0,d=0;dn&&(o=n):o=n;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");o>i/2&&(o=i/2);for(var s=0;s>8,n=r%256,i.push(n),i.push(o);return i}(t,e.length-r),e,r,o)}function A(e,t,r){return 0===t&&r===e.length?o.fromByteArray(e):o.fromByteArray(e.slice(t,r))}function R(e,t,r){r=Math.min(e.length,r);for(var o=[],n=t;n239?4:c>223?3:c>191?2:1;if(n+l<=r)switch(l){case 1:c<128&&(h=c);break;case 2:128==(192&(i=e[n+1]))&&(u=(31&c)<<6|63&i)>127&&(h=u);break;case 3:i=e[n+1],s=e[n+2],128==(192&i)&&128==(192&s)&&(u=(15&c)<<12|(63&i)<<6|63&s)>2047&&(u<55296||u>57343)&&(h=u);break;case 4:i=e[n+1],s=e[n+2],a=e[n+3],128==(192&i)&&128==(192&s)&&128==(192&a)&&(u=(15&c)<<18|(63&i)<<12|(63&s)<<6|63&a)>65535&&u<1114112&&(h=u)}null===h?(h=65533,l=1):h>65535&&(h-=65536,o.push(h>>>10&1023|55296),h=56320|1023&h),o.push(h),n+=l}return function(e){var t=e.length;if(t<=4096)return String.fromCharCode.apply(String,e);var r="",o=0;for(;o0&&(e=this.toString("hex",0,r).match(/.{2}/g).join(" "),this.length>r&&(e+=" ... ")),""},u.prototype.compare=function(e,t,r,o,n){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===r&&(r=e?e.length:0),void 0===o&&(o=0),void 0===n&&(n=this.length),t<0||r>e.length||o<0||n>this.length)throw new RangeError("out of range index");if(o>=n&&t>=r)return 0;if(o>=n)return-1;if(t>=r)return 1;if(this===e)return 0;for(var i=(n>>>=0)-(o>>>=0),s=(r>>>=0)-(t>>>=0),a=Math.min(i,s),c=this.slice(o,n),h=e.slice(t,r),l=0;ln)&&(r=n),e.length>0&&(r<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");o||(o="utf8");for(var i=!1;;)switch(o){case"hex":return _(this,e,t,r);case"utf8":case"utf-8":return b(this,e,t,r);case"ascii":return w(this,e,t,r);case"latin1":case"binary":return P(this,e,t,r);case"base64":return E(this,e,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return T(this,e,t,r);default:if(i)throw new TypeError("Unknown encoding: "+o);o=(""+o).toLowerCase(),i=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function S(e,t,r){var o="";r=Math.min(e.length,r);for(var n=t;no)&&(r=o);for(var n="",i=t;ir)throw new RangeError("Trying to access beyond buffer length")}function x(e,t,r,o,n,i){if(!u.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>n||te.length)throw new RangeError("Index out of range")}function I(e,t,r,o){t<0&&(t=65535+t+1);for(var n=0,i=Math.min(e.length-r,2);n>>8*(o?n:1-n)}function N(e,t,r,o){t<0&&(t=4294967295+t+1);for(var n=0,i=Math.min(e.length-r,4);n>>8*(o?n:3-n)&255}function U(e,t,r,o,n,i){if(r+o>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function j(e,t,r,o,i){return i||U(e,0,r,4),n.write(e,t,r,o,23,4),r+4}function F(e,t,r,o,i){return i||U(e,0,r,8),n.write(e,t,r,o,52,8),r+8}u.prototype.slice=function(e,t){var r,o=this.length;if((e=~~e)<0?(e+=o)<0&&(e=0):e>o&&(e=o),(t=void 0===t?o:~~t)<0?(t+=o)<0&&(t=0):t>o&&(t=o),t0&&(n*=256);)o+=this[e+--t]*n;return o},u.prototype.readUInt8=function(e,t){return t||C(e,1,this.length),this[e]},u.prototype.readUInt16LE=function(e,t){return t||C(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUInt16BE=function(e,t){return t||C(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUInt32LE=function(e,t){return t||C(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},u.prototype.readUInt32BE=function(e,t){return t||C(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readIntLE=function(e,t,r){e|=0,t|=0,r||C(e,t,this.length);for(var o=this[e],n=1,i=0;++i=(n*=128)&&(o-=Math.pow(2,8*t)),o},u.prototype.readIntBE=function(e,t,r){e|=0,t|=0,r||C(e,t,this.length);for(var o=t,n=1,i=this[e+--o];o>0&&(n*=256);)i+=this[e+--o]*n;return i>=(n*=128)&&(i-=Math.pow(2,8*t)),i},u.prototype.readInt8=function(e,t){return t||C(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},u.prototype.readInt16LE=function(e,t){t||C(e,2,this.length);var r=this[e]|this[e+1]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt16BE=function(e,t){t||C(e,2,this.length);var r=this[e+1]|this[e]<<8;return 32768&r?4294901760|r:r},u.prototype.readInt32LE=function(e,t){return t||C(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,t){return t||C(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readFloatLE=function(e,t){return t||C(e,4,this.length),n.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,t){return t||C(e,4,this.length),n.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,t){return t||C(e,8,this.length),n.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,t){return t||C(e,8,this.length),n.read(this,e,!1,52,8)},u.prototype.writeUIntLE=function(e,t,r,o){(e=+e,t|=0,r|=0,o)||x(this,e,t,r,Math.pow(2,8*r)-1,0);var n=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+n]=e/i&255;return t+r},u.prototype.writeUInt8=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,1,255,0),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},u.prototype.writeUInt16LE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):I(this,e,t,!0),t+2},u.prototype.writeUInt16BE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):I(this,e,t,!1),t+2},u.prototype.writeUInt32LE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):N(this,e,t,!0),t+4},u.prototype.writeUInt32BE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},u.prototype.writeIntLE=function(e,t,r,o){if(e=+e,t|=0,!o){var n=Math.pow(2,8*r-1);x(this,e,t,r,n-1,-n)}var i=0,s=1,a=0;for(this[t]=255&e;++i>0)-a&255;return t+r},u.prototype.writeIntBE=function(e,t,r,o){if(e=+e,t|=0,!o){var n=Math.pow(2,8*r-1);x(this,e,t,r,n-1,-n)}var i=r-1,s=1,a=0;for(this[t+i]=255&e;--i>=0&&(s*=256);)e<0&&0===a&&0!==this[t+i+1]&&(a=1),this[t+i]=(e/s>>0)-a&255;return t+r},u.prototype.writeInt8=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,1,127,-128),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},u.prototype.writeInt16LE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):I(this,e,t,!0),t+2},u.prototype.writeInt16BE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):I(this,e,t,!1),t+2},u.prototype.writeInt32LE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,4,2147483647,-2147483648),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):N(this,e,t,!0),t+4},u.prototype.writeInt32BE=function(e,t,r){return e=+e,t|=0,r||x(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},u.prototype.writeFloatLE=function(e,t,r){return j(this,e,t,!0,r)},u.prototype.writeFloatBE=function(e,t,r){return j(this,e,t,!1,r)},u.prototype.writeDoubleLE=function(e,t,r){return F(this,e,t,!0,r)},u.prototype.writeDoubleBE=function(e,t,r){return F(this,e,t,!1,r)},u.prototype.copy=function(e,t,r,o){if(r||(r=0),o||0===o||(o=this.length),t>=e.length&&(t=e.length),t||(t=0),o>0&&o=this.length)throw new RangeError("sourceStart out of bounds");if(o<0)throw new RangeError("sourceEnd out of bounds");o>this.length&&(o=this.length),e.length-t=0;--n)e[n+t]=this[n+r];else if(i<1e3||!u.TYPED_ARRAY_SUPPORT)for(n=0;n>>=0,r=void 0===r?this.length:r>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&r<57344){if(!n){if(r>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(s+1===o){(t-=3)>-1&&i.push(239,191,189);continue}n=r;continue}if(r<56320){(t-=3)>-1&&i.push(239,191,189),n=r;continue}r=65536+(n-55296<<10|r-56320)}else n&&(t-=3)>-1&&i.push(239,191,189);if(n=null,r<128){if((t-=1)<0)break;i.push(r)}else if(r<2048){if((t-=2)<0)break;i.push(r>>6|192,63&r|128)}else if(r<65536){if((t-=3)<0)break;i.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return i}function q(e){return o.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(D,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function J(e,t,r,o){for(var n=0;n=t.length||n>=e.length);++n)t[n+r]=e[n];return n}}).call(this,r(6))},function(e,t,r){"use strict";t.byteLength=function(e){var t=c(e),r=t[0],o=t[1];return 3*(r+o)/4-o},t.toByteArray=function(e){var t,r,o=c(e),s=o[0],a=o[1],u=new i(function(e,t,r){return 3*(t+r)/4-r}(0,s,a)),h=0,l=a>0?s-4:s;for(r=0;r>16&255,u[h++]=t>>8&255,u[h++]=255&t;2===a&&(t=n[e.charCodeAt(r)]<<2|n[e.charCodeAt(r+1)]>>4,u[h++]=255&t);1===a&&(t=n[e.charCodeAt(r)]<<10|n[e.charCodeAt(r+1)]<<4|n[e.charCodeAt(r+2)]>>2,u[h++]=t>>8&255,u[h++]=255&t);return u},t.fromByteArray=function(e){for(var t,r=e.length,n=r%3,i=[],s=0,a=r-n;sa?a:s+16383));1===n?(t=e[r-1],i.push(o[t>>2]+o[t<<4&63]+"==")):2===n&&(t=(e[r-2]<<8)+e[r-1],i.push(o[t>>10]+o[t>>4&63]+o[t<<2&63]+"="));return i.join("")};for(var o=[],n=[],i="undefined"!=typeof Uint8Array?Uint8Array:Array,s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",a=0,u=s.length;a0)throw new Error("Invalid string. Length must be a multiple of 4");var r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}function h(e,t,r){for(var n,i,s=[],a=t;a>18&63]+o[i>>12&63]+o[i>>6&63]+o[63&i]);return s.join("")}n["-".charCodeAt(0)]=62,n["_".charCodeAt(0)]=63},function(e,t){ +/* eslint-disable no-proto */ + + + +var base64 = __webpack_require__(/*! base64-js */ "./node_modules/base64-js/index.js") +var ieee754 = __webpack_require__(/*! ieee754 */ "./node_modules/ieee754/index.js") +var isArray = __webpack_require__(/*! isarray */ "./node_modules/isarray/index.js") + +exports.Buffer = Buffer +exports.SlowBuffer = SlowBuffer +exports.INSPECT_MAX_BYTES = 50 + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Use Object implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * Due to various browser bugs, sometimes the Object implementation will be used even + * when the browser supports typed arrays. + * + * Note: + * + * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, + * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. + * + * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. + * + * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of + * incorrect length in some situations. + + * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they + * get the Object implementation, which is slower but behaves correctly. + */ +Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined + ? global.TYPED_ARRAY_SUPPORT + : typedArraySupport() + +/* + * Export kMaxLength after typed array support is determined. + */ +exports.kMaxLength = kMaxLength() + +function typedArraySupport () { + try { + var arr = new Uint8Array(1) + arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }} + return arr.foo() === 42 && // typed array instances can be augmented + typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` + arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` + } catch (e) { + return false + } +} + +function kMaxLength () { + return Buffer.TYPED_ARRAY_SUPPORT + ? 0x7fffffff + : 0x3fffffff +} + +function createBuffer (that, length) { + if (kMaxLength() < length) { + throw new RangeError('Invalid typed array length') + } + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = new Uint8Array(length) + that.__proto__ = Buffer.prototype + } else { + // Fallback: Return an object instance of the Buffer class + if (that === null) { + that = new Buffer(length) + } + that.length = length + } + + return that +} + +/** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + +function Buffer (arg, encodingOrOffset, length) { + if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { + return new Buffer(arg, encodingOrOffset, length) + } + + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new Error( + 'If encoding is specified then the first argument must be a string' + ) + } + return allocUnsafe(this, arg) + } + return from(this, arg, encodingOrOffset, length) +} + +Buffer.poolSize = 8192 // not used by this implementation + +// TODO: Legacy, not needed anymore. Remove in next major version. +Buffer._augment = function (arr) { + arr.__proto__ = Buffer.prototype + return arr +} + +function from (that, value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('"value" argument must not be a number') + } + + if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { + return fromArrayBuffer(that, value, encodingOrOffset, length) + } + + if (typeof value === 'string') { + return fromString(that, value, encodingOrOffset) + } + + return fromObject(that, value) +} + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ +Buffer.from = function (value, encodingOrOffset, length) { + return from(null, value, encodingOrOffset, length) +} + +if (Buffer.TYPED_ARRAY_SUPPORT) { + Buffer.prototype.__proto__ = Uint8Array.prototype + Buffer.__proto__ = Uint8Array + if (typeof Symbol !== 'undefined' && Symbol.species && + Buffer[Symbol.species] === Buffer) { + // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true + }) + } +} + +function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be a number') + } else if (size < 0) { + throw new RangeError('"size" argument must not be negative') + } +} + +function alloc (that, size, fill, encoding) { + assertSize(size) + if (size <= 0) { + return createBuffer(that, size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(that, size).fill(fill, encoding) + : createBuffer(that, size).fill(fill) + } + return createBuffer(that, size) +} + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ +Buffer.alloc = function (size, fill, encoding) { + return alloc(null, size, fill, encoding) +} + +function allocUnsafe (that, size) { + assertSize(size) + that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) + if (!Buffer.TYPED_ARRAY_SUPPORT) { + for (var i = 0; i < size; ++i) { + that[i] = 0 + } + } + return that +} + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ +Buffer.allocUnsafe = function (size) { + return allocUnsafe(null, size) +} +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ +Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(null, size) +} + +function fromString (that, string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8' + } + + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('"encoding" must be a valid string encoding') + } + + var length = byteLength(string, encoding) | 0 + that = createBuffer(that, length) + + var actual = that.write(string, encoding) + + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + that = that.slice(0, actual) + } + + return that +} + +function fromArrayLike (that, array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0 + that = createBuffer(that, length) + for (var i = 0; i < length; i += 1) { + that[i] = array[i] & 255 + } + return that +} + +function fromArrayBuffer (that, array, byteOffset, length) { + array.byteLength // this throws if `array` is not a valid ArrayBuffer + + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('\'offset\' is out of bounds') + } + + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('\'length\' is out of bounds') + } + + if (byteOffset === undefined && length === undefined) { + array = new Uint8Array(array) + } else if (length === undefined) { + array = new Uint8Array(array, byteOffset) + } else { + array = new Uint8Array(array, byteOffset, length) + } + + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = array + that.__proto__ = Buffer.prototype + } else { + // Fallback: Return an object instance of the Buffer class + that = fromArrayLike(that, array) + } + return that +} + +function fromObject (that, obj) { + if (Buffer.isBuffer(obj)) { + var len = checked(obj.length) | 0 + that = createBuffer(that, len) + + if (that.length === 0) { + return that + } + + obj.copy(that, 0, 0, len) + return that + } + + if (obj) { + if ((typeof ArrayBuffer !== 'undefined' && + obj.buffer instanceof ArrayBuffer) || 'length' in obj) { + if (typeof obj.length !== 'number' || isnan(obj.length)) { + return createBuffer(that, 0) + } + return fromArrayLike(that, obj) + } + + if (obj.type === 'Buffer' && isArray(obj.data)) { + return fromArrayLike(that, obj.data) + } + } + + throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') +} + +function checked (length) { + // Note: cannot use `length < kMaxLength()` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= kMaxLength()) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + kMaxLength().toString(16) + ' bytes') + } + return length | 0 +} + +function SlowBuffer (length) { + if (+length != length) { // eslint-disable-line eqeqeq + length = 0 + } + return Buffer.alloc(+length) +} + +Buffer.isBuffer = function isBuffer (b) { + return !!(b != null && b._isBuffer) +} + +Buffer.compare = function compare (a, b) { + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError('Arguments must be Buffers') + } + + if (a === b) return 0 + + var x = a.length + var y = b.length + + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i] + y = b[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.concat = function concat (list, length) { + if (!isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + + if (list.length === 0) { + return Buffer.alloc(0) + } + + var i + if (length === undefined) { + length = 0 + for (i = 0; i < list.length; ++i) { + length += list[i].length + } + } + + var buffer = Buffer.allocUnsafe(length) + var pos = 0 + for (i = 0; i < list.length; ++i) { + var buf = list[i] + if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + buf.copy(buffer, pos) + pos += buf.length + } + return buffer +} + +function byteLength (string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length + } + if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && + (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + string = '' + string + } + + var len = string.length + if (len === 0) return 0 + + // Use a for loop to avoid recursion + var loweredCase = false + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + case undefined: + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) return utf8ToBytes(string).length // assume utf8 + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} +Buffer.byteLength = byteLength + +function slowToString (encoding, start, end) { + var loweredCase = false + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0 + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' + } + + if (end === undefined || end > this.length) { + end = this.length + } + + if (end <= 0) { + return '' + } + + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0 + start >>>= 0 + + if (end <= start) { + return '' + } + + if (!encoding) encoding = 'utf8' + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase() + loweredCase = true + } + } +} + +// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect +// Buffer instances. +Buffer.prototype._isBuffer = true + +function swap (b, n, m) { + var i = b[n] + b[n] = b[m] + b[m] = i +} + +Buffer.prototype.swap16 = function swap16 () { + var len = this.length + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1) + } + return this +} + +Buffer.prototype.swap32 = function swap32 () { + var len = this.length + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3) + swap(this, i + 1, i + 2) + } + return this +} + +Buffer.prototype.swap64 = function swap64 () { + var len = this.length + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7) + swap(this, i + 1, i + 6) + swap(this, i + 2, i + 5) + swap(this, i + 3, i + 4) + } + return this +} + +Buffer.prototype.toString = function toString () { + var length = this.length | 0 + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) +} + +Buffer.prototype.equals = function equals (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 +} + +Buffer.prototype.inspect = function inspect () { + var str = '' + var max = exports.INSPECT_MAX_BYTES + if (this.length > 0) { + str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') + if (this.length > max) str += ' ... ' + } + return '' +} + +Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (!Buffer.isBuffer(target)) { + throw new TypeError('Argument must be a Buffer') + } + + if (start === undefined) { + start = 0 + } + if (end === undefined) { + end = target ? target.length : 0 + } + if (thisStart === undefined) { + thisStart = 0 + } + if (thisEnd === undefined) { + thisEnd = this.length + } + + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } + + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 + } + + start >>>= 0 + end >>>= 0 + thisStart >>>= 0 + thisEnd >>>= 0 + + if (this === target) return 0 + + var x = thisEnd - thisStart + var y = end - start + var len = Math.min(x, y) + + var thisCopy = this.slice(thisStart, thisEnd) + var targetCopy = target.slice(start, end) + + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i] + y = targetCopy[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset + byteOffset = 0 + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000 + } + byteOffset = +byteOffset // Coerce to Number. + if (isNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1) + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1 + } else if (byteOffset < 0) { + if (dir) byteOffset = 0 + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding) + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF // Search for a byte value [0-255] + if (Buffer.TYPED_ARRAY_SUPPORT && + typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } + } + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') +} + +function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + var indexSize = 1 + var arrLength = arr.length + var valLength = val.length + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase() + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2 + arrLength /= 2 + valLength /= 2 + byteOffset /= 2 + } + } + + function read (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } + + var i + if (dir) { + var foundIndex = -1 + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex + foundIndex = -1 + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength + for (i = byteOffset; i >= 0; i--) { + var found = true + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false + break + } + } + if (found) return i + } + } + + return -1 +} + +Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 +} + +Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) +} + +Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) +} + +function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + var remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + + // must be an even number of digits + var strLen = string.length + if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') + + if (length > strLen / 2) { + length = strLen / 2 + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16) + if (isNaN(parsed)) return i + buf[offset + i] = parsed + } + return i +} + +function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) +} + +function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) +} + +function latin1Write (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) +} + +function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) +} + +function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) +} + +Buffer.prototype.write = function write (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8' + length = this.length + offset = 0 + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset + length = this.length + offset = 0 + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset | 0 + if (isFinite(length)) { + length = length | 0 + if (encoding === undefined) encoding = 'utf8' + } else { + encoding = length + length = undefined + } + // legacy write(string, encoding, offset, length) - remove in v0.13 + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } + + var remaining = this.length - offset + if (length === undefined || length > remaining) length = remaining + + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } + + if (!encoding) encoding = 'utf8' + + var loweredCase = false + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) + + case 'ascii': + return asciiWrite(this, string, offset, length) + + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length) + + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} + +Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end) + var res = [] + + var i = start + while (i < end) { + var firstByte = buf[i] + var codePoint = null + var bytesPerSequence = (firstByte > 0xEF) ? 4 + : (firstByte > 0xDF) ? 3 + : (firstByte > 0xBF) ? 2 + : 1 + + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte + } + break + case 2: + secondByte = buf[i + 1] + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint + } + } + break + case 3: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint + } + } + break + case 4: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + fourthByte = buf[i + 3] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint + } + } + } + } + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD + bytesPerSequence = 1 + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000 + res.push(codePoint >>> 10 & 0x3FF | 0xD800) + codePoint = 0xDC00 | codePoint & 0x3FF + } + + res.push(codePoint) + i += bytesPerSequence + } + + return decodeCodePointsArray(res) +} + +// Based on http://stackoverflow.com/a/22747272/680742, the browser with +// the lowest limit is Chrome, with 0x10000 args. +// We go 1 magnitude less, for safety +var MAX_ARGUMENTS_LENGTH = 0x1000 + +function decodeCodePointsArray (codePoints) { + var len = codePoints.length + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + var res = '' + var i = 0 + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ) + } + return res +} + +function asciiSlice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F) + } + return ret +} + +function latin1Slice (buf, start, end) { + var ret = '' + end = Math.min(buf.length, end) + + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]) + } + return ret +} + +function hexSlice (buf, start, end) { + var len = buf.length + + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len + + var out = '' + for (var i = start; i < end; ++i) { + out += toHex(buf[i]) + } + return out +} + +function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end) + var res = '' + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) + } + return res +} + +Buffer.prototype.slice = function slice (start, end) { + var len = this.length + start = ~~start + end = end === undefined ? len : ~~end + + if (start < 0) { + start += len + if (start < 0) start = 0 + } else if (start > len) { + start = len + } + + if (end < 0) { + end += len + if (end < 0) end = 0 + } else if (end > len) { + end = len + } + + if (end < start) end = start + + var newBuf + if (Buffer.TYPED_ARRAY_SUPPORT) { + newBuf = this.subarray(start, end) + newBuf.__proto__ = Buffer.prototype + } else { + var sliceLen = end - start + newBuf = new Buffer(sliceLen, undefined) + for (var i = 0; i < sliceLen; ++i) { + newBuf[i] = this[i + start] + } + } + + return newBuf +} + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') +} + +Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + + return val +} + +Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) { + checkOffset(offset, byteLength, this.length) + } + + var val = this[offset + --byteLength] + var mul = 1 + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul + } + + return val +} + +Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length) + return this[offset] +} + +Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length) + return this[offset] | (this[offset + 1] << 8) +} + +Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length) + return (this[offset] << 8) | this[offset + 1] +} + +Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) +} + +Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) +} + +Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var val = this[offset] + var mul = 1 + var i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + var i = byteLength + var mul = 1 + var val = this[offset + --i] + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length) + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) +} + +Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset] | (this[offset + 1] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length) + var val = this[offset + 1] | (this[offset] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) +} + +Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) +} + +Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, true, 23, 4) +} + +Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, false, 23, 4) +} + +Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, true, 52, 8) +} + +Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, false, 52, 8) +} + +function checkInt (buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') +} + +Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var mul = 1 + var i = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset | 0 + byteLength = byteLength | 0 + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + var i = byteLength - 1 + var mul = 1 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) + this[offset] = (value & 0xff) + return offset + 1 +} + +function objectWriteUInt16 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffff + value + 1 + for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { + buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> + (littleEndian ? i : 1 - i) * 8 + } +} + +Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + } else { + objectWriteUInt16(this, value, offset, true) + } + return offset + 2 +} + +Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + } else { + objectWriteUInt16(this, value, offset, false) + } + return offset + 2 +} + +function objectWriteUInt32 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffffffff + value + 1 + for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { + buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff + } +} + +Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) + } else { + objectWriteUInt32(this, value, offset, true) + } + return offset + 4 +} + +Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + } else { + objectWriteUInt32(this, value, offset, false) + } + return offset + 4 +} + +Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = 0 + var mul = 1 + var sub = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + var i = byteLength - 1 + var mul = 1 + var sub = 0 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) + if (value < 0) value = 0xff + value + 1 + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + } else { + objectWriteUInt16(this, value, offset, true) + } + return offset + 2 +} + +Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + } else { + objectWriteUInt16(this, value, offset, false) + } + return offset + 2 +} + +Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) + } else { + objectWriteUInt32(this, value, offset, true) + } + return offset + 4 +} + +Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value + offset = offset | 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (value < 0) value = 0xffffffff + value + 1 + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + } else { + objectWriteUInt32(this, value, offset, false) + } + return offset + 4 +} + +function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') +} + +function writeFloat (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + ieee754.write(buf, value, offset, littleEndian, 23, 4) + return offset + 4 +} + +Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) +} + +function writeDouble (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + ieee754.write(buf, value, offset, littleEndian, 52, 8) + return offset + 8 +} + +Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (targetStart >= target.length) targetStart = target.length + if (!targetStart) targetStart = 0 + if (end > 0 && end < start) end = start + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') + if (end < 0) throw new RangeError('sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) end = this.length + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start + } + + var len = end - start + var i + + if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start] + } + } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { + // ascending copy from start + for (i = 0; i < len; ++i) { + target[i + targetStart] = this[i + start] + } + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, start + len), + targetStart + ) + } + + return len +} + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start + start = 0 + end = this.length + } else if (typeof end === 'string') { + encoding = end + end = this.length + } + if (val.length === 1) { + var code = val.charCodeAt(0) + if (code < 256) { + val = code + } + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + } else if (typeof val === 'number') { + val = val & 255 + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } + + if (end <= start) { + return this + } + + start = start >>> 0 + end = end === undefined ? this.length : end >>> 0 + + if (!val) val = 0 + + var i + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val + } + } else { + var bytes = Buffer.isBuffer(val) + ? val + : utf8ToBytes(new Buffer(val, encoding).toString()) + var len = bytes.length + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len] + } + } + + return this +} + +// HELPER FUNCTIONS +// ================ + +var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g + +function base64clean (str) { + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = stringtrim(str).replace(INVALID_BASE64_RE, '') + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '=' + } + return str +} + +function stringtrim (str) { + if (str.trim) return str.trim() + return str.replace(/^\s+|\s+$/g, '') +} + +function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) +} + +function utf8ToBytes (string, units) { + units = units || Infinity + var codePoint + var length = string.length + var leadSurrogate = null + var bytes = [] + + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i) + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } + + // valid lead + leadSurrogate = codePoint + + continue + } + + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = codePoint + continue + } + + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + } + + leadSurrogate = null + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint) + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else { + throw new Error('Invalid code point') + } + } + + return bytes +} + +function asciiToBytes (str) { + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray +} + +function utf16leToBytes (str, units) { + var c, hi, lo + var byteArray = [] + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i) + hi = c >> 8 + lo = c % 256 + byteArray.push(lo) + byteArray.push(hi) + } + + return byteArray +} + +function base64ToBytes (str) { + return base64.toByteArray(base64clean(str)) +} + +function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i] + } + return i +} + +function isnan (val) { + return val !== val // eslint-disable-line no-self-compare +} + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../webpack/buildin/global.js */ "./node_modules/webpack/buildin/global.js"))) + +/***/ }), + +/***/ "./node_modules/ieee754/index.js": +/*!***************************************!*\ + !*** ./node_modules/ieee754/index.js ***! + \***************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ -t.read=function(e,t,r,o,n){var i,s,a=8*n-o-1,u=(1<>1,h=-7,l=r?n-1:0,d=r?-1:1,f=e[t+l];for(l+=d,i=f&(1<<-h)-1,f>>=-h,h+=a;h>0;i=256*i+e[t+l],l+=d,h-=8);for(s=i&(1<<-h)-1,i>>=-h,h+=o;h>0;s=256*s+e[t+l],l+=d,h-=8);if(0===i)i=1-c;else{if(i===u)return s?NaN:1/0*(f?-1:1);s+=Math.pow(2,o),i-=c}return(f?-1:1)*s*Math.pow(2,i-o)},t.write=function(e,t,r,o,n,i){var s,a,u,c=8*i-n-1,h=(1<>1,d=23===n?Math.pow(2,-24)-Math.pow(2,-77):0,f=o?0:i-1,p=o?1:-1,m=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(a=isNaN(t)?1:0,s=h):(s=Math.floor(Math.log(t)/Math.LN2),t*(u=Math.pow(2,-s))<1&&(s--,u*=2),(t+=s+l>=1?d/u:d*Math.pow(2,1-l))*u>=2&&(s++,u/=2),s+l>=h?(a=0,s=h):s+l>=1?(a=(t*u-1)*Math.pow(2,n),s+=l):(a=t*Math.pow(2,l-1)*Math.pow(2,n),s=0));n>=8;e[r+f]=255&a,f+=p,a/=256,n-=8);for(s=s<0;e[r+f]=255&s,f+=p,s/=256,c-=8);e[r+f-p]|=128*m}},function(e,t){var r={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==r.call(e)}},function(e,t,r){var o,n,i;n=[],void 0===(i="function"==typeof(o=function(){var e,t,r,o;Object.keys||(Object.keys=(e=Object.prototype.hasOwnProperty,t=!{toString:null}.propertyIsEnumerable("toString"),o=(r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"]).length,function(n){if("object"!=typeof n&&"function"!=typeof n||null===n)throw new TypeError("Object.keys called on non-object");var i=[];for(var s in n)e.call(n,s)&&i.push(s);if(t)for(var a=0;a>>0;if(0===r)return-1;var o=0;if(arguments.length>1&&((o=Number(arguments[1]))!=o?o=0:0!==o&&o!==1/0&&o!==-1/0&&(o=(o>0||-1)*Math.floor(Math.abs(o)))),o>=r)return-1;for(var n=o>=0?o:Math.max(r-Math.abs(o),0);n0&&(t+=h.suffices["*"]&&r||",",h.suffices["*"]&&u&&(t+=h.name+"=")),t+=a?encodeURIComponent(l[f]).replace(/!/g,"%21"):s(l[f])}else if("object"==typeof l){u&&!h.suffices["*"]&&(t+=h.name+"=");var p=!0;for(var m in l)p||(t+=h.suffices["*"]&&r||","),p=!1,t+=a?encodeURIComponent(m).replace(/!/g,"%21"):s(m),t+=h.suffices["*"]?"=":",",t+=a?encodeURIComponent(l[m]).replace(/!/g,"%21"):s(l[m])}else u&&(t+=h.name,c&&""===l||(t+="=")),null!=h.truncate&&(l=l.substring(0,h.truncate)),t+=a?encodeURIComponent(l).replace(/!/g,"%21"):s(l)}return t};return b.varNames=h,{prefix:o,substitution:b}}function u(e){if(!(this instanceof u))return new u(e);for(var t=e.split("{"),r=[t.shift()],o=[],n=[],i=[];t.length>0;){var s=t.shift(),c=s.split("}")[0],h=s.substring(c.length+1),l=a(c);n.push(l.substitution),o.push(l.prefix),r.push(h),i=i.concat(l.substitution.varNames)}this.fill=function(e){for(var t=r[0],o=0;o0&&"/"===t.charAt(e.length-1)||"#"===r.charAt(0)||"?"===r.charAt(0))return!0}return!1}(t,e.id)&&void 0===this.schemas[e.id]&&(this.schemas[e.id]=e),e)if("enum"!==o)if("object"==typeof e[o])this.searchSchemas(e[o],t);else if("$ref"===o){var n=m(e[o]);n&&void 0===this.schemas[n]&&void 0===this.missingMap[n]&&(this.missingMap[n]=n)}},c.prototype.addSchema=function(e,t){if("string"!=typeof e||void 0===t){if("object"!=typeof e||"string"!=typeof e.id)return;e=(t=e).id}e===m(e)+"#"&&(e=m(e)),this.schemas[e]=t,delete this.missingMap[e],g(t,e),this.searchSchemas(t,e)},c.prototype.getSchemaMap=function(){var e={};for(var t in this.schemas)e[t]=this.schemas[t];return e},c.prototype.getSchemaUris=function(e){var t=[];for(var r in this.schemas)e&&!e.test(r)||t.push(r);return t},c.prototype.getMissingUris=function(e){var t=[];for(var r in this.missingMap)e&&!e.test(r)||t.push(r);return t},c.prototype.dropSchemas=function(){this.schemas={},this.reset()},c.prototype.reset=function(){this.missing=[],this.missingMap={},this.errors=[]},c.prototype.validateAll=function(e,t,r,o,n){var i;if(!(t=this.resolveRefs(t)))return null;if(t instanceof P)return this.errors.push(t),t;var s,a=this.errors.length,u=null,c=null;if(this.checkRecursive&&e&&"object"==typeof e){if(i=!this.scanned.length,e[this.validatedSchemasKey]){var h=e[this.validatedSchemasKey].indexOf(t);if(-1!==h)return this.errors=this.errors.concat(e[this.validationErrorsKey][h]),null}if(Object.isFrozen(e)&&-1!==(s=this.scannedFrozen.indexOf(e))){var l=this.scannedFrozenSchemas[s].indexOf(t);if(-1!==l)return this.errors=this.errors.concat(this.scannedFrozenValidationErrors[s][l]),null}if(this.scanned.push(e),Object.isFrozen(e))-1===s&&(s=this.scannedFrozen.length,this.scannedFrozen.push(e),this.scannedFrozenSchemas.push([])),u=this.scannedFrozenSchemas[s].length,this.scannedFrozenSchemas[s][u]=t,this.scannedFrozenValidationErrors[s][u]=[];else{if(!e[this.validatedSchemasKey])try{Object.defineProperty(e,this.validatedSchemasKey,{value:[],configurable:!0}),Object.defineProperty(e,this.validationErrorsKey,{value:[],configurable:!0})}catch(t){e[this.validatedSchemasKey]=[],e[this.validationErrorsKey]=[]}c=e[this.validatedSchemasKey].length,e[this.validatedSchemasKey][c]=t,e[this.validationErrorsKey][c]=[]}}var d=this.errors.length,f=this.validateBasic(e,t,n)||this.validateNumeric(e,t,n)||this.validateString(e,t,n)||this.validateArray(e,t,n)||this.validateObject(e,t,n)||this.validateCombinations(e,t,n)||this.validateHypermedia(e,t,n)||this.validateFormat(e,t,n)||this.validateDefinedKeywords(e,t,n)||null;if(i){for(;this.scanned.length;)delete this.scanned.pop()[this.validatedSchemasKey];this.scannedFrozen=[],this.scannedFrozenSchemas=[]}if(f||d!==this.errors.length)for(;r&&r.length||o&&o.length;){var p=r&&r.length?""+r.pop():null,m=o&&o.length?""+o.pop():null;f&&(f=f.prefixWith(p,m)),this.prefixErrors(d,p,m)}return null!==u?this.scannedFrozenValidationErrors[s][u]=this.errors.slice(a):null!==c&&(e[this.validationErrorsKey][c]=this.errors.slice(a)),this.handleError(f)},c.prototype.validateFormat=function(e,t){if("string"!=typeof t.format||!this.formatValidators[t.format])return null;var r=this.formatValidators[t.format].call(null,e,t);return"string"==typeof r||"number"==typeof r?this.createError(v.FORMAT_CUSTOM,{message:r},"","/format",null,e,t):r&&"object"==typeof r?this.createError(v.FORMAT_CUSTOM,{message:r.message||"?"},r.dataPath||"",r.schemaPath||"/format",null,e,t):null},c.prototype.validateDefinedKeywords=function(e,t,r){for(var o in this.definedKeywords)if(void 0!==t[o])for(var n=this.definedKeywords[o],i=0;i=l&&ot.maximum)return this.createError(v.NUMBER_MAXIMUM,{value:e,maximum:t.maximum},"","/maximum",null,e,t);if(t.exclusiveMaximum&&e===t.maximum)return this.createError(v.NUMBER_MAXIMUM_EXCLUSIVE,{value:e,maximum:t.maximum},"","/exclusiveMaximum",null,e,t)}return null},c.prototype.validateNaN=function(e,t){return"number"!=typeof e?null:!0===isNaN(e)||e===1/0||e===-1/0?this.createError(v.NUMBER_NOT_A_NUMBER,{value:e},"","/type",null,e,t):null},c.prototype.validateString=function(e,t,r){return this.validateStringLength(e,t,r)||this.validateStringPattern(e,t,r)||null},c.prototype.validateStringLength=function(e,t){return"string"!=typeof e?null:void 0!==t.minLength&&e.lengtht.maxLength?this.createError(v.STRING_LENGTH_LONG,{length:e.length,maximum:t.maxLength},"","/maxLength",null,e,t):null},c.prototype.validateStringPattern=function(e,t){if("string"!=typeof e||"string"!=typeof t.pattern&&!(t.pattern instanceof RegExp))return null;var r;if(t.pattern instanceof RegExp)r=t.pattern;else{var o,n="",i=t.pattern.match(/^\/(.+)\/([img]*)$/);i?(o=i[1],n=i[2]):o=t.pattern,r=new RegExp(o,n)}return r.test(e)?null:this.createError(v.STRING_PATTERN,{pattern:t.pattern},"","/pattern",null,e,t)},c.prototype.validateArray=function(e,t,r){return Array.isArray(e)&&(this.validateArrayLength(e,t,r)||this.validateArrayUniqueItems(e,t,r)||this.validateArrayItems(e,t,r))||null},c.prototype.validateArrayLength=function(e,t){var r;return void 0!==t.minItems&&e.lengtht.maxItems&&(r=this.createError(v.ARRAY_LENGTH_LONG,{length:e.length,maximum:t.maxItems},"","/maxItems",null,e,t),this.handleError(r))?r:null},c.prototype.validateArrayUniqueItems=function(e,t){if(t.uniqueItems)for(var r=0;rt.maxProperties&&(r=this.createError(v.OBJECT_PROPERTIES_MAXIMUM,{propertyCount:o.length,maximum:t.maxProperties},"","/maxProperties",null,e,t),this.handleError(r))?r:null},c.prototype.validateObjectRequiredProperties=function(e,t){if(void 0!==t.required)for(var r=0;r 10000");if(void 0!==v[e])throw new Error("Error already defined: "+e+" as "+v[e]);if(void 0!==_[t])throw new Error("Error code already used: "+_[t]+" as "+t);for(var o in v[e]=t,_[t]=e,w[e]=w[t]=r,E){var n=E[o];n[e]&&(n[t]=n[t]||n[e])}},reset:function(){n.reset(),this.error=null,this.missing=[],this.valid=!0},missing:[],error:null,valid:!0,normSchema:g,resolveUrl:p,getDocumentUri:m,errorCodes:v};return i.language(t||"en"),i}();return T.addLanguage("en-gb",w),T.tv4=T,T})?o.apply(t,n):o)||(e.exports=i)},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BaseClientTypes=void 0;class o{constructor(){this.uris={},this.schemas={},this.aliases={}}declare(e,t,r,o){const n=e+"/"+t;if(o.extends){const t=o.extends.split("/"),r=1===t.length?e+"/"+t.shift():t.join("/"),i=this.uris[r];if(!i)throw"Type '"+n+"' tries to extend unknown schema '"+r+"'";o.extends=this.schemas[i]}this.uris[n]=r,this.aliases[r]=n,this.schemas[r]=o}resolveAlias(e){return this.uris[e]}getSchema(e){return this.schemas[e]}inScope(e){const t=e.length,r={};for(const o in this.uris)if(o.substr(0,t+1)===e+"/"){const e=this.uris[o];r[e]=this.schemas[e]}return r}}t.BaseClientTypes=o;const n=new o;t.default=n},function(e,t,r){"use strict";class o extends Error{constructor(e){super();const t=new Error("Schema not found: "+e);return t.name="SchemaNotFound",t}}e.exports=o},function(e,t,r){"use strict";e.exports=class{constructor(e){this._itemsRev={},this._storage={},this._canPropagate=!1,this.defaultValue=e,this.activatePropagation()}get(e){e=e.toLowerCase();let t=this._storage[e];return void 0===t&&(t=this.defaultValue,this._storage[e]=t),t}set(e,t){return e=e.toLowerCase(),this._storage[e]===t||(this._storage[e]=t,t||delete this._itemsRev[e],this._updateParentFolderItemRev(e,t),this._canPropagate&&this._propagate(e)),t}delete(e){return this.set(e,null)}deactivatePropagation(){return this._canPropagate=!1,!0}activatePropagation(){return this._canPropagate||(this._generateFolderRev("/"),this._canPropagate=!0),!0}_hashCode(e){let t=0;if(0===e.length)return t;for(let r=0;r0&&(r=this._generateHash(e))}return this.set(e,r),r}}},function(e,t,r){var o; +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = ((value * c) - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} + + +/***/ }), + +/***/ "./node_modules/isarray/index.js": +/*!***************************************!*\ + !*** ./node_modules/isarray/index.js ***! + \***************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +var toString = {}.toString; + +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; + + +/***/ }), + +/***/ "./node_modules/tv4/tv4.js": +/*!*********************************!*\ + !*** ./node_modules/tv4/tv4.js ***! + \*********************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* +Author: Geraint Luff and others +Year: 2013 + +This code is released into the "public domain" by its author(s). Anybody may use, alter and distribute the code without restriction. The author makes no guarantees, and takes no liability of any kind for use of this code. + +If you find a bug or make an improvement, it would be courteous to let the author know, but it is not compulsory. +*/ +(function (global, factory) { + if (true) { + // AMD. Register as an anonymous module. + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else {} +}(this, function () { + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FObject%2Fkeys +if (!Object.keys) { + Object.keys = (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function (obj) { + if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { + throw new TypeError('Object.keys called on non-object'); + } + + var result = []; + + for (var prop in obj) { + if (hasOwnProperty.call(obj, prop)) { + result.push(prop); + } + } + + if (hasDontEnumBug) { + for (var i=0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) { + result.push(dontEnums[i]); + } + } + } + return result; + }; + })(); +} +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create +if (!Object.create) { + Object.create = (function(){ + function F(){} + + return function(o){ + if (arguments.length !== 1) { + throw new Error('Object.create implementation only accepts one parameter.'); + } + F.prototype = o; + return new F(); + }; + })(); +} +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FisArray +if(!Array.isArray) { + Array.isArray = function (vArg) { + return Object.prototype.toString.call(vArg) === "[object Array]"; + }; +} +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FindexOf +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { + if (this === null) { + throw new TypeError(); + } + var t = Object(this); + var len = t.length >>> 0; + + if (len === 0) { + return -1; + } + var n = 0; + if (arguments.length > 1) { + n = Number(arguments[1]); + if (n !== n) { // shortcut for verifying if it's NaN + n = 0; + } else if (n !== 0 && n !== Infinity && n !== -Infinity) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + if (n >= len) { + return -1; + } + var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); + for (; k < len; k++) { + if (k in t && t[k] === searchElement) { + return k; + } + } + return -1; + }; +} + +// Grungey Object.isFrozen hack +if (!Object.isFrozen) { + Object.isFrozen = function (obj) { + var key = "tv4_test_frozen_key"; + while (obj.hasOwnProperty(key)) { + key += Math.random(); + } + try { + obj[key] = true; + delete obj[key]; + return false; + } catch (e) { + return true; + } + }; +} +// Based on: https://github.com/geraintluff/uri-templates, but with all the de-substitution stuff removed + +var uriTemplateGlobalModifiers = { + "+": true, + "#": true, + ".": true, + "/": true, + ";": true, + "?": true, + "&": true +}; +var uriTemplateSuffices = { + "*": true +}; + +function notReallyPercentEncode(string) { + return encodeURI(string).replace(/%25[0-9][0-9]/g, function (doubleEncoded) { + return "%" + doubleEncoded.substring(3); + }); +} + +function uriTemplateSubstitution(spec) { + var modifier = ""; + if (uriTemplateGlobalModifiers[spec.charAt(0)]) { + modifier = spec.charAt(0); + spec = spec.substring(1); + } + var separator = ""; + var prefix = ""; + var shouldEscape = true; + var showVariables = false; + var trimEmptyString = false; + if (modifier === '+') { + shouldEscape = false; + } else if (modifier === ".") { + prefix = "."; + separator = "."; + } else if (modifier === "/") { + prefix = "/"; + separator = "/"; + } else if (modifier === '#') { + prefix = "#"; + shouldEscape = false; + } else if (modifier === ';') { + prefix = ";"; + separator = ";"; + showVariables = true; + trimEmptyString = true; + } else if (modifier === '?') { + prefix = "?"; + separator = "&"; + showVariables = true; + } else if (modifier === '&') { + prefix = "&"; + separator = "&"; + showVariables = true; + } + + var varNames = []; + var varList = spec.split(","); + var varSpecs = []; + var varSpecMap = {}; + for (var i = 0; i < varList.length; i++) { + var varName = varList[i]; + var truncate = null; + if (varName.indexOf(":") !== -1) { + var parts = varName.split(":"); + varName = parts[0]; + truncate = parseInt(parts[1], 10); + } + var suffices = {}; + while (uriTemplateSuffices[varName.charAt(varName.length - 1)]) { + suffices[varName.charAt(varName.length - 1)] = true; + varName = varName.substring(0, varName.length - 1); + } + var varSpec = { + truncate: truncate, + name: varName, + suffices: suffices + }; + varSpecs.push(varSpec); + varSpecMap[varName] = varSpec; + varNames.push(varName); + } + var subFunction = function (valueFunction) { + var result = ""; + var startIndex = 0; + for (var i = 0; i < varSpecs.length; i++) { + var varSpec = varSpecs[i]; + var value = valueFunction(varSpec.name); + if (value === null || value === undefined || (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0)) { + startIndex++; + continue; + } + if (i === startIndex) { + result += prefix; + } else { + result += (separator || ","); + } + if (Array.isArray(value)) { + if (showVariables) { + result += varSpec.name + "="; + } + for (var j = 0; j < value.length; j++) { + if (j > 0) { + result += varSpec.suffices['*'] ? (separator || ",") : ","; + if (varSpec.suffices['*'] && showVariables) { + result += varSpec.name + "="; + } + } + result += shouldEscape ? encodeURIComponent(value[j]).replace(/!/g, "%21") : notReallyPercentEncode(value[j]); + } + } else if (typeof value === "object") { + if (showVariables && !varSpec.suffices['*']) { + result += varSpec.name + "="; + } + var first = true; + for (var key in value) { + if (!first) { + result += varSpec.suffices['*'] ? (separator || ",") : ","; + } + first = false; + result += shouldEscape ? encodeURIComponent(key).replace(/!/g, "%21") : notReallyPercentEncode(key); + result += varSpec.suffices['*'] ? '=' : ","; + result += shouldEscape ? encodeURIComponent(value[key]).replace(/!/g, "%21") : notReallyPercentEncode(value[key]); + } + } else { + if (showVariables) { + result += varSpec.name; + if (!trimEmptyString || value !== "") { + result += "="; + } + } + if (varSpec.truncate != null) { + value = value.substring(0, varSpec.truncate); + } + result += shouldEscape ? encodeURIComponent(value).replace(/!/g, "%21"): notReallyPercentEncode(value); + } + } + return result; + }; + subFunction.varNames = varNames; + return { + prefix: prefix, + substitution: subFunction + }; +} + +function UriTemplate(template) { + if (!(this instanceof UriTemplate)) { + return new UriTemplate(template); + } + var parts = template.split("{"); + var textParts = [parts.shift()]; + var prefixes = []; + var substitutions = []; + var varNames = []; + while (parts.length > 0) { + var part = parts.shift(); + var spec = part.split("}")[0]; + var remainder = part.substring(spec.length + 1); + var funcs = uriTemplateSubstitution(spec); + substitutions.push(funcs.substitution); + prefixes.push(funcs.prefix); + textParts.push(remainder); + varNames = varNames.concat(funcs.substitution.varNames); + } + this.fill = function (valueFunction) { + var result = textParts[0]; + for (var i = 0; i < substitutions.length; i++) { + var substitution = substitutions[i]; + result += substitution(valueFunction); + result += textParts[i + 1]; + } + return result; + }; + this.varNames = varNames; + this.template = template; +} +UriTemplate.prototype = { + toString: function () { + return this.template; + }, + fillFromObject: function (obj) { + return this.fill(function (varName) { + return obj[varName]; + }); + } +}; +var ValidatorContext = function ValidatorContext(parent, collectMultiple, errorReporter, checkRecursive, trackUnknownProperties) { + this.missing = []; + this.missingMap = {}; + this.formatValidators = parent ? Object.create(parent.formatValidators) : {}; + this.schemas = parent ? Object.create(parent.schemas) : {}; + this.collectMultiple = collectMultiple; + this.errors = []; + this.handleError = collectMultiple ? this.collectError : this.returnError; + if (checkRecursive) { + this.checkRecursive = true; + this.scanned = []; + this.scannedFrozen = []; + this.scannedFrozenSchemas = []; + this.scannedFrozenValidationErrors = []; + this.validatedSchemasKey = 'tv4_validation_id'; + this.validationErrorsKey = 'tv4_validation_errors_id'; + } + if (trackUnknownProperties) { + this.trackUnknownProperties = true; + this.knownPropertyPaths = {}; + this.unknownPropertyPaths = {}; + } + this.errorReporter = errorReporter || defaultErrorReporter('en'); + if (typeof this.errorReporter === 'string') { + throw new Error('debug'); + } + this.definedKeywords = {}; + if (parent) { + for (var key in parent.definedKeywords) { + this.definedKeywords[key] = parent.definedKeywords[key].slice(0); + } + } +}; +ValidatorContext.prototype.defineKeyword = function (keyword, keywordFunction) { + this.definedKeywords[keyword] = this.definedKeywords[keyword] || []; + this.definedKeywords[keyword].push(keywordFunction); +}; +ValidatorContext.prototype.createError = function (code, messageParams, dataPath, schemaPath, subErrors, data, schema) { + var error = new ValidationError(code, messageParams, dataPath, schemaPath, subErrors); + error.message = this.errorReporter(error, data, schema); + return error; +}; +ValidatorContext.prototype.returnError = function (error) { + return error; +}; +ValidatorContext.prototype.collectError = function (error) { + if (error) { + this.errors.push(error); + } + return null; +}; +ValidatorContext.prototype.prefixErrors = function (startIndex, dataPath, schemaPath) { + for (var i = startIndex; i < this.errors.length; i++) { + this.errors[i] = this.errors[i].prefixWith(dataPath, schemaPath); + } + return this; +}; +ValidatorContext.prototype.banUnknownProperties = function (data, schema) { + for (var unknownPath in this.unknownPropertyPaths) { + var error = this.createError(ErrorCodes.UNKNOWN_PROPERTY, {path: unknownPath}, unknownPath, "", null, data, schema); + var result = this.handleError(error); + if (result) { + return result; + } + } + return null; +}; + +ValidatorContext.prototype.addFormat = function (format, validator) { + if (typeof format === 'object') { + for (var key in format) { + this.addFormat(key, format[key]); + } + return this; + } + this.formatValidators[format] = validator; +}; +ValidatorContext.prototype.resolveRefs = function (schema, urlHistory) { + if (schema['$ref'] !== undefined) { + urlHistory = urlHistory || {}; + if (urlHistory[schema['$ref']]) { + return this.createError(ErrorCodes.CIRCULAR_REFERENCE, {urls: Object.keys(urlHistory).join(', ')}, '', '', null, undefined, schema); + } + urlHistory[schema['$ref']] = true; + schema = this.getSchema(schema['$ref'], urlHistory); + } + return schema; +}; +ValidatorContext.prototype.getSchema = function (url, urlHistory) { + var schema; + if (this.schemas[url] !== undefined) { + schema = this.schemas[url]; + return this.resolveRefs(schema, urlHistory); + } + var baseUrl = url; + var fragment = ""; + if (url.indexOf('#') !== -1) { + fragment = url.substring(url.indexOf("#") + 1); + baseUrl = url.substring(0, url.indexOf("#")); + } + if (typeof this.schemas[baseUrl] === 'object') { + schema = this.schemas[baseUrl]; + var pointerPath = decodeURIComponent(fragment); + if (pointerPath === "") { + return this.resolveRefs(schema, urlHistory); + } else if (pointerPath.charAt(0) !== "/") { + return undefined; + } + var parts = pointerPath.split("/").slice(1); + for (var i = 0; i < parts.length; i++) { + var component = parts[i].replace(/~1/g, "/").replace(/~0/g, "~"); + if (schema[component] === undefined) { + schema = undefined; + break; + } + schema = schema[component]; + } + if (schema !== undefined) { + return this.resolveRefs(schema, urlHistory); + } + } + if (this.missing[baseUrl] === undefined) { + this.missing.push(baseUrl); + this.missing[baseUrl] = baseUrl; + this.missingMap[baseUrl] = baseUrl; + } +}; +ValidatorContext.prototype.searchSchemas = function (schema, url) { + if (Array.isArray(schema)) { + for (var i = 0; i < schema.length; i++) { + this.searchSchemas(schema[i], url); + } + } else if (schema && typeof schema === "object") { + if (typeof schema.id === "string") { + if (isTrustedUrl(url, schema.id)) { + if (this.schemas[schema.id] === undefined) { + this.schemas[schema.id] = schema; + } + } + } + for (var key in schema) { + if (key !== "enum") { + if (typeof schema[key] === "object") { + this.searchSchemas(schema[key], url); + } else if (key === "$ref") { + var uri = getDocumentUri(schema[key]); + if (uri && this.schemas[uri] === undefined && this.missingMap[uri] === undefined) { + this.missingMap[uri] = uri; + } + } + } + } + } +}; +ValidatorContext.prototype.addSchema = function (url, schema) { + //overload + if (typeof url !== 'string' || typeof schema === 'undefined') { + if (typeof url === 'object' && typeof url.id === 'string') { + schema = url; + url = schema.id; + } + else { + return; + } + } + if (url === getDocumentUri(url) + "#") { + // Remove empty fragment + url = getDocumentUri(url); + } + this.schemas[url] = schema; + delete this.missingMap[url]; + normSchema(schema, url); + this.searchSchemas(schema, url); +}; + +ValidatorContext.prototype.getSchemaMap = function () { + var map = {}; + for (var key in this.schemas) { + map[key] = this.schemas[key]; + } + return map; +}; + +ValidatorContext.prototype.getSchemaUris = function (filterRegExp) { + var list = []; + for (var key in this.schemas) { + if (!filterRegExp || filterRegExp.test(key)) { + list.push(key); + } + } + return list; +}; + +ValidatorContext.prototype.getMissingUris = function (filterRegExp) { + var list = []; + for (var key in this.missingMap) { + if (!filterRegExp || filterRegExp.test(key)) { + list.push(key); + } + } + return list; +}; + +ValidatorContext.prototype.dropSchemas = function () { + this.schemas = {}; + this.reset(); +}; +ValidatorContext.prototype.reset = function () { + this.missing = []; + this.missingMap = {}; + this.errors = []; +}; + +ValidatorContext.prototype.validateAll = function (data, schema, dataPathParts, schemaPathParts, dataPointerPath) { + var topLevel; + schema = this.resolveRefs(schema); + if (!schema) { + return null; + } else if (schema instanceof ValidationError) { + this.errors.push(schema); + return schema; + } + + var startErrorCount = this.errors.length; + var frozenIndex, scannedFrozenSchemaIndex = null, scannedSchemasIndex = null; + if (this.checkRecursive && data && typeof data === 'object') { + topLevel = !this.scanned.length; + if (data[this.validatedSchemasKey]) { + var schemaIndex = data[this.validatedSchemasKey].indexOf(schema); + if (schemaIndex !== -1) { + this.errors = this.errors.concat(data[this.validationErrorsKey][schemaIndex]); + return null; + } + } + if (Object.isFrozen(data)) { + frozenIndex = this.scannedFrozen.indexOf(data); + if (frozenIndex !== -1) { + var frozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].indexOf(schema); + if (frozenSchemaIndex !== -1) { + this.errors = this.errors.concat(this.scannedFrozenValidationErrors[frozenIndex][frozenSchemaIndex]); + return null; + } + } + } + this.scanned.push(data); + if (Object.isFrozen(data)) { + if (frozenIndex === -1) { + frozenIndex = this.scannedFrozen.length; + this.scannedFrozen.push(data); + this.scannedFrozenSchemas.push([]); + } + scannedFrozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].length; + this.scannedFrozenSchemas[frozenIndex][scannedFrozenSchemaIndex] = schema; + this.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = []; + } else { + if (!data[this.validatedSchemasKey]) { + try { + Object.defineProperty(data, this.validatedSchemasKey, { + value: [], + configurable: true + }); + Object.defineProperty(data, this.validationErrorsKey, { + value: [], + configurable: true + }); + } catch (e) { + //IE 7/8 workaround + data[this.validatedSchemasKey] = []; + data[this.validationErrorsKey] = []; + } + } + scannedSchemasIndex = data[this.validatedSchemasKey].length; + data[this.validatedSchemasKey][scannedSchemasIndex] = schema; + data[this.validationErrorsKey][scannedSchemasIndex] = []; + } + } + + var errorCount = this.errors.length; + var error = this.validateBasic(data, schema, dataPointerPath) + || this.validateNumeric(data, schema, dataPointerPath) + || this.validateString(data, schema, dataPointerPath) + || this.validateArray(data, schema, dataPointerPath) + || this.validateObject(data, schema, dataPointerPath) + || this.validateCombinations(data, schema, dataPointerPath) + || this.validateHypermedia(data, schema, dataPointerPath) + || this.validateFormat(data, schema, dataPointerPath) + || this.validateDefinedKeywords(data, schema, dataPointerPath) + || null; + + if (topLevel) { + while (this.scanned.length) { + var item = this.scanned.pop(); + delete item[this.validatedSchemasKey]; + } + this.scannedFrozen = []; + this.scannedFrozenSchemas = []; + } + + if (error || errorCount !== this.errors.length) { + while ((dataPathParts && dataPathParts.length) || (schemaPathParts && schemaPathParts.length)) { + var dataPart = (dataPathParts && dataPathParts.length) ? "" + dataPathParts.pop() : null; + var schemaPart = (schemaPathParts && schemaPathParts.length) ? "" + schemaPathParts.pop() : null; + if (error) { + error = error.prefixWith(dataPart, schemaPart); + } + this.prefixErrors(errorCount, dataPart, schemaPart); + } + } + + if (scannedFrozenSchemaIndex !== null) { + this.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = this.errors.slice(startErrorCount); + } else if (scannedSchemasIndex !== null) { + data[this.validationErrorsKey][scannedSchemasIndex] = this.errors.slice(startErrorCount); + } + + return this.handleError(error); +}; +ValidatorContext.prototype.validateFormat = function (data, schema) { + if (typeof schema.format !== 'string' || !this.formatValidators[schema.format]) { + return null; + } + var errorMessage = this.formatValidators[schema.format].call(null, data, schema); + if (typeof errorMessage === 'string' || typeof errorMessage === 'number') { + return this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage}, '', '/format', null, data, schema); + } else if (errorMessage && typeof errorMessage === 'object') { + return this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage.message || "?"}, errorMessage.dataPath || '', errorMessage.schemaPath || "/format", null, data, schema); + } + return null; +}; +ValidatorContext.prototype.validateDefinedKeywords = function (data, schema, dataPointerPath) { + for (var key in this.definedKeywords) { + if (typeof schema[key] === 'undefined') { + continue; + } + var validationFunctions = this.definedKeywords[key]; + for (var i = 0; i < validationFunctions.length; i++) { + var func = validationFunctions[i]; + var result = func(data, schema[key], schema, dataPointerPath); + if (typeof result === 'string' || typeof result === 'number') { + return this.createError(ErrorCodes.KEYWORD_CUSTOM, {key: key, message: result}, '', '', null, data, schema).prefixWith(null, key); + } else if (result && typeof result === 'object') { + var code = result.code; + if (typeof code === 'string') { + if (!ErrorCodes[code]) { + throw new Error('Undefined error code (use defineError): ' + code); + } + code = ErrorCodes[code]; + } else if (typeof code !== 'number') { + code = ErrorCodes.KEYWORD_CUSTOM; + } + var messageParams = (typeof result.message === 'object') ? result.message : {key: key, message: result.message || "?"}; + var schemaPath = result.schemaPath || ("/" + key.replace(/~/g, '~0').replace(/\//g, '~1')); + return this.createError(code, messageParams, result.dataPath || null, schemaPath, null, data, schema); + } + } + } + return null; +}; + +function recursiveCompare(A, B) { + if (A === B) { + return true; + } + if (A && B && typeof A === "object" && typeof B === "object") { + if (Array.isArray(A) !== Array.isArray(B)) { + return false; + } else if (Array.isArray(A)) { + if (A.length !== B.length) { + return false; + } + for (var i = 0; i < A.length; i++) { + if (!recursiveCompare(A[i], B[i])) { + return false; + } + } + } else { + var key; + for (key in A) { + if (B[key] === undefined && A[key] !== undefined) { + return false; + } + } + for (key in B) { + if (A[key] === undefined && B[key] !== undefined) { + return false; + } + } + for (key in A) { + if (!recursiveCompare(A[key], B[key])) { + return false; + } + } + } + return true; + } + return false; +} + +ValidatorContext.prototype.validateBasic = function validateBasic(data, schema, dataPointerPath) { + var error; + if (error = this.validateType(data, schema, dataPointerPath)) { + return error.prefixWith(null, "type"); + } + if (error = this.validateEnum(data, schema, dataPointerPath)) { + return error.prefixWith(null, "type"); + } + return null; +}; + +ValidatorContext.prototype.validateType = function validateType(data, schema) { + if (schema.type === undefined) { + return null; + } + var dataType = typeof data; + if (data === null) { + dataType = "null"; + } else if (Array.isArray(data)) { + dataType = "array"; + } + var allowedTypes = schema.type; + if (!Array.isArray(allowedTypes)) { + allowedTypes = [allowedTypes]; + } + + for (var i = 0; i < allowedTypes.length; i++) { + var type = allowedTypes[i]; + if (type === dataType || (type === "integer" && dataType === "number" && (data % 1 === 0))) { + return null; + } + } + return this.createError(ErrorCodes.INVALID_TYPE, {type: dataType, expected: allowedTypes.join("/")}, '', '', null, data, schema); +}; + +ValidatorContext.prototype.validateEnum = function validateEnum(data, schema) { + if (schema["enum"] === undefined) { + return null; + } + for (var i = 0; i < schema["enum"].length; i++) { + var enumVal = schema["enum"][i]; + if (recursiveCompare(data, enumVal)) { + return null; + } + } + return this.createError(ErrorCodes.ENUM_MISMATCH, {value: (typeof JSON !== 'undefined') ? JSON.stringify(data) : data}, '', '', null, data, schema); +}; + +ValidatorContext.prototype.validateNumeric = function validateNumeric(data, schema, dataPointerPath) { + return this.validateMultipleOf(data, schema, dataPointerPath) + || this.validateMinMax(data, schema, dataPointerPath) + || this.validateNaN(data, schema, dataPointerPath) + || null; +}; + +var CLOSE_ENOUGH_LOW = Math.pow(2, -51); +var CLOSE_ENOUGH_HIGH = 1 - CLOSE_ENOUGH_LOW; +ValidatorContext.prototype.validateMultipleOf = function validateMultipleOf(data, schema) { + var multipleOf = schema.multipleOf || schema.divisibleBy; + if (multipleOf === undefined) { + return null; + } + if (typeof data === "number") { + var remainder = (data/multipleOf)%1; + if (remainder >= CLOSE_ENOUGH_LOW && remainder < CLOSE_ENOUGH_HIGH) { + return this.createError(ErrorCodes.NUMBER_MULTIPLE_OF, {value: data, multipleOf: multipleOf}, '', '', null, data, schema); + } + } + return null; +}; + +ValidatorContext.prototype.validateMinMax = function validateMinMax(data, schema) { + if (typeof data !== "number") { + return null; + } + if (schema.minimum !== undefined) { + if (data < schema.minimum) { + return this.createError(ErrorCodes.NUMBER_MINIMUM, {value: data, minimum: schema.minimum}, '', '/minimum', null, data, schema); + } + if (schema.exclusiveMinimum && data === schema.minimum) { + return this.createError(ErrorCodes.NUMBER_MINIMUM_EXCLUSIVE, {value: data, minimum: schema.minimum}, '', '/exclusiveMinimum', null, data, schema); + } + } + if (schema.maximum !== undefined) { + if (data > schema.maximum) { + return this.createError(ErrorCodes.NUMBER_MAXIMUM, {value: data, maximum: schema.maximum}, '', '/maximum', null, data, schema); + } + if (schema.exclusiveMaximum && data === schema.maximum) { + return this.createError(ErrorCodes.NUMBER_MAXIMUM_EXCLUSIVE, {value: data, maximum: schema.maximum}, '', '/exclusiveMaximum', null, data, schema); + } + } + return null; +}; + +ValidatorContext.prototype.validateNaN = function validateNaN(data, schema) { + if (typeof data !== "number") { + return null; + } + if (isNaN(data) === true || data === Infinity || data === -Infinity) { + return this.createError(ErrorCodes.NUMBER_NOT_A_NUMBER, {value: data}, '', '/type', null, data, schema); + } + return null; +}; + +ValidatorContext.prototype.validateString = function validateString(data, schema, dataPointerPath) { + return this.validateStringLength(data, schema, dataPointerPath) + || this.validateStringPattern(data, schema, dataPointerPath) + || null; +}; + +ValidatorContext.prototype.validateStringLength = function validateStringLength(data, schema) { + if (typeof data !== "string") { + return null; + } + if (schema.minLength !== undefined) { + if (data.length < schema.minLength) { + return this.createError(ErrorCodes.STRING_LENGTH_SHORT, {length: data.length, minimum: schema.minLength}, '', '/minLength', null, data, schema); + } + } + if (schema.maxLength !== undefined) { + if (data.length > schema.maxLength) { + return this.createError(ErrorCodes.STRING_LENGTH_LONG, {length: data.length, maximum: schema.maxLength}, '', '/maxLength', null, data, schema); + } + } + return null; +}; + +ValidatorContext.prototype.validateStringPattern = function validateStringPattern(data, schema) { + if (typeof data !== "string" || (typeof schema.pattern !== "string" && !(schema.pattern instanceof RegExp))) { + return null; + } + var regexp; + if (schema.pattern instanceof RegExp) { + regexp = schema.pattern; + } + else { + var body, flags = ''; + // Check for regular expression literals + // @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.5 + var literal = schema.pattern.match(/^\/(.+)\/([img]*)$/); + if (literal) { + body = literal[1]; + flags = literal[2]; + } + else { + body = schema.pattern; + } + regexp = new RegExp(body, flags); + } + if (!regexp.test(data)) { + return this.createError(ErrorCodes.STRING_PATTERN, {pattern: schema.pattern}, '', '/pattern', null, data, schema); + } + return null; +}; + +ValidatorContext.prototype.validateArray = function validateArray(data, schema, dataPointerPath) { + if (!Array.isArray(data)) { + return null; + } + return this.validateArrayLength(data, schema, dataPointerPath) + || this.validateArrayUniqueItems(data, schema, dataPointerPath) + || this.validateArrayItems(data, schema, dataPointerPath) + || null; +}; + +ValidatorContext.prototype.validateArrayLength = function validateArrayLength(data, schema) { + var error; + if (schema.minItems !== undefined) { + if (data.length < schema.minItems) { + error = this.createError(ErrorCodes.ARRAY_LENGTH_SHORT, {length: data.length, minimum: schema.minItems}, '', '/minItems', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + if (schema.maxItems !== undefined) { + if (data.length > schema.maxItems) { + error = this.createError(ErrorCodes.ARRAY_LENGTH_LONG, {length: data.length, maximum: schema.maxItems}, '', '/maxItems', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + return null; +}; + +ValidatorContext.prototype.validateArrayUniqueItems = function validateArrayUniqueItems(data, schema) { + if (schema.uniqueItems) { + for (var i = 0; i < data.length; i++) { + for (var j = i + 1; j < data.length; j++) { + if (recursiveCompare(data[i], data[j])) { + var error = this.createError(ErrorCodes.ARRAY_UNIQUE, {match1: i, match2: j}, '', '/uniqueItems', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + } + } + return null; +}; + +ValidatorContext.prototype.validateArrayItems = function validateArrayItems(data, schema, dataPointerPath) { + if (schema.items === undefined) { + return null; + } + var error, i; + if (Array.isArray(schema.items)) { + for (i = 0; i < data.length; i++) { + if (i < schema.items.length) { + if (error = this.validateAll(data[i], schema.items[i], [i], ["items", i], dataPointerPath + "/" + i)) { + return error; + } + } else if (schema.additionalItems !== undefined) { + if (typeof schema.additionalItems === "boolean") { + if (!schema.additionalItems) { + error = (this.createError(ErrorCodes.ARRAY_ADDITIONAL_ITEMS, {}, '/' + i, '/additionalItems', null, data, schema)); + if (this.handleError(error)) { + return error; + } + } + } else if (error = this.validateAll(data[i], schema.additionalItems, [i], ["additionalItems"], dataPointerPath + "/" + i)) { + return error; + } + } + } + } else { + for (i = 0; i < data.length; i++) { + if (error = this.validateAll(data[i], schema.items, [i], ["items"], dataPointerPath + "/" + i)) { + return error; + } + } + } + return null; +}; + +ValidatorContext.prototype.validateObject = function validateObject(data, schema, dataPointerPath) { + if (typeof data !== "object" || data === null || Array.isArray(data)) { + return null; + } + return this.validateObjectMinMaxProperties(data, schema, dataPointerPath) + || this.validateObjectRequiredProperties(data, schema, dataPointerPath) + || this.validateObjectProperties(data, schema, dataPointerPath) + || this.validateObjectDependencies(data, schema, dataPointerPath) + || null; +}; + +ValidatorContext.prototype.validateObjectMinMaxProperties = function validateObjectMinMaxProperties(data, schema) { + var keys = Object.keys(data); + var error; + if (schema.minProperties !== undefined) { + if (keys.length < schema.minProperties) { + error = this.createError(ErrorCodes.OBJECT_PROPERTIES_MINIMUM, {propertyCount: keys.length, minimum: schema.minProperties}, '', '/minProperties', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + if (schema.maxProperties !== undefined) { + if (keys.length > schema.maxProperties) { + error = this.createError(ErrorCodes.OBJECT_PROPERTIES_MAXIMUM, {propertyCount: keys.length, maximum: schema.maxProperties}, '', '/maxProperties', null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + return null; +}; + +ValidatorContext.prototype.validateObjectRequiredProperties = function validateObjectRequiredProperties(data, schema) { + if (schema.required !== undefined) { + for (var i = 0; i < schema.required.length; i++) { + var key = schema.required[i]; + if (data[key] === undefined) { + var error = this.createError(ErrorCodes.OBJECT_REQUIRED, {key: key}, '', '/required/' + i, null, data, schema); + if (this.handleError(error)) { + return error; + } + } + } + } + return null; +}; + +ValidatorContext.prototype.validateObjectProperties = function validateObjectProperties(data, schema, dataPointerPath) { + var error; + for (var key in data) { + var keyPointerPath = dataPointerPath + "/" + key.replace(/~/g, '~0').replace(/\//g, '~1'); + var foundMatch = false; + if (schema.properties !== undefined && schema.properties[key] !== undefined) { + foundMatch = true; + if (error = this.validateAll(data[key], schema.properties[key], [key], ["properties", key], keyPointerPath)) { + return error; + } + } + if (schema.patternProperties !== undefined) { + for (var patternKey in schema.patternProperties) { + var regexp = new RegExp(patternKey); + if (regexp.test(key)) { + foundMatch = true; + if (error = this.validateAll(data[key], schema.patternProperties[patternKey], [key], ["patternProperties", patternKey], keyPointerPath)) { + return error; + } + } + } + } + if (!foundMatch) { + if (schema.additionalProperties !== undefined) { + if (this.trackUnknownProperties) { + this.knownPropertyPaths[keyPointerPath] = true; + delete this.unknownPropertyPaths[keyPointerPath]; + } + if (typeof schema.additionalProperties === "boolean") { + if (!schema.additionalProperties) { + error = this.createError(ErrorCodes.OBJECT_ADDITIONAL_PROPERTIES, {key: key}, '', '/additionalProperties', null, data, schema).prefixWith(key, null); + if (this.handleError(error)) { + return error; + } + } + } else { + if (error = this.validateAll(data[key], schema.additionalProperties, [key], ["additionalProperties"], keyPointerPath)) { + return error; + } + } + } else if (this.trackUnknownProperties && !this.knownPropertyPaths[keyPointerPath]) { + this.unknownPropertyPaths[keyPointerPath] = true; + } + } else if (this.trackUnknownProperties) { + this.knownPropertyPaths[keyPointerPath] = true; + delete this.unknownPropertyPaths[keyPointerPath]; + } + } + return null; +}; + +ValidatorContext.prototype.validateObjectDependencies = function validateObjectDependencies(data, schema, dataPointerPath) { + var error; + if (schema.dependencies !== undefined) { + for (var depKey in schema.dependencies) { + if (data[depKey] !== undefined) { + var dep = schema.dependencies[depKey]; + if (typeof dep === "string") { + if (data[dep] === undefined) { + error = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: dep}, '', '', null, data, schema).prefixWith(null, depKey).prefixWith(null, "dependencies"); + if (this.handleError(error)) { + return error; + } + } + } else if (Array.isArray(dep)) { + for (var i = 0; i < dep.length; i++) { + var requiredKey = dep[i]; + if (data[requiredKey] === undefined) { + error = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: requiredKey}, '', '/' + i, null, data, schema).prefixWith(null, depKey).prefixWith(null, "dependencies"); + if (this.handleError(error)) { + return error; + } + } + } + } else { + if (error = this.validateAll(data, dep, [], ["dependencies", depKey], dataPointerPath)) { + return error; + } + } + } + } + } + return null; +}; + +ValidatorContext.prototype.validateCombinations = function validateCombinations(data, schema, dataPointerPath) { + return this.validateAllOf(data, schema, dataPointerPath) + || this.validateAnyOf(data, schema, dataPointerPath) + || this.validateOneOf(data, schema, dataPointerPath) + || this.validateNot(data, schema, dataPointerPath) + || null; +}; + +ValidatorContext.prototype.validateAllOf = function validateAllOf(data, schema, dataPointerPath) { + if (schema.allOf === undefined) { + return null; + } + var error; + for (var i = 0; i < schema.allOf.length; i++) { + var subSchema = schema.allOf[i]; + if (error = this.validateAll(data, subSchema, [], ["allOf", i], dataPointerPath)) { + return error; + } + } + return null; +}; + +ValidatorContext.prototype.validateAnyOf = function validateAnyOf(data, schema, dataPointerPath) { + if (schema.anyOf === undefined) { + return null; + } + var errors = []; + var startErrorCount = this.errors.length; + var oldUnknownPropertyPaths, oldKnownPropertyPaths; + if (this.trackUnknownProperties) { + oldUnknownPropertyPaths = this.unknownPropertyPaths; + oldKnownPropertyPaths = this.knownPropertyPaths; + } + var errorAtEnd = true; + for (var i = 0; i < schema.anyOf.length; i++) { + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = {}; + this.knownPropertyPaths = {}; + } + var subSchema = schema.anyOf[i]; + + var errorCount = this.errors.length; + var error = this.validateAll(data, subSchema, [], ["anyOf", i], dataPointerPath); + + if (error === null && errorCount === this.errors.length) { + this.errors = this.errors.slice(0, startErrorCount); + + if (this.trackUnknownProperties) { + for (var knownKey in this.knownPropertyPaths) { + oldKnownPropertyPaths[knownKey] = true; + delete oldUnknownPropertyPaths[knownKey]; + } + for (var unknownKey in this.unknownPropertyPaths) { + if (!oldKnownPropertyPaths[unknownKey]) { + oldUnknownPropertyPaths[unknownKey] = true; + } + } + // We need to continue looping so we catch all the property definitions, but we don't want to return an error + errorAtEnd = false; + continue; + } + + return null; + } + if (error) { + errors.push(error.prefixWith(null, "" + i).prefixWith(null, "anyOf")); + } + } + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = oldUnknownPropertyPaths; + this.knownPropertyPaths = oldKnownPropertyPaths; + } + if (errorAtEnd) { + errors = errors.concat(this.errors.slice(startErrorCount)); + this.errors = this.errors.slice(0, startErrorCount); + return this.createError(ErrorCodes.ANY_OF_MISSING, {}, "", "/anyOf", errors, data, schema); + } +}; + +ValidatorContext.prototype.validateOneOf = function validateOneOf(data, schema, dataPointerPath) { + if (schema.oneOf === undefined) { + return null; + } + var validIndex = null; + var errors = []; + var startErrorCount = this.errors.length; + var oldUnknownPropertyPaths, oldKnownPropertyPaths; + if (this.trackUnknownProperties) { + oldUnknownPropertyPaths = this.unknownPropertyPaths; + oldKnownPropertyPaths = this.knownPropertyPaths; + } + for (var i = 0; i < schema.oneOf.length; i++) { + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = {}; + this.knownPropertyPaths = {}; + } + var subSchema = schema.oneOf[i]; + + var errorCount = this.errors.length; + var error = this.validateAll(data, subSchema, [], ["oneOf", i], dataPointerPath); + + if (error === null && errorCount === this.errors.length) { + if (validIndex === null) { + validIndex = i; + } else { + this.errors = this.errors.slice(0, startErrorCount); + return this.createError(ErrorCodes.ONE_OF_MULTIPLE, {index1: validIndex, index2: i}, "", "/oneOf", null, data, schema); + } + if (this.trackUnknownProperties) { + for (var knownKey in this.knownPropertyPaths) { + oldKnownPropertyPaths[knownKey] = true; + delete oldUnknownPropertyPaths[knownKey]; + } + for (var unknownKey in this.unknownPropertyPaths) { + if (!oldKnownPropertyPaths[unknownKey]) { + oldUnknownPropertyPaths[unknownKey] = true; + } + } + } + } else if (error) { + errors.push(error); + } + } + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = oldUnknownPropertyPaths; + this.knownPropertyPaths = oldKnownPropertyPaths; + } + if (validIndex === null) { + errors = errors.concat(this.errors.slice(startErrorCount)); + this.errors = this.errors.slice(0, startErrorCount); + return this.createError(ErrorCodes.ONE_OF_MISSING, {}, "", "/oneOf", errors, data, schema); + } else { + this.errors = this.errors.slice(0, startErrorCount); + } + return null; +}; + +ValidatorContext.prototype.validateNot = function validateNot(data, schema, dataPointerPath) { + if (schema.not === undefined) { + return null; + } + var oldErrorCount = this.errors.length; + var oldUnknownPropertyPaths, oldKnownPropertyPaths; + if (this.trackUnknownProperties) { + oldUnknownPropertyPaths = this.unknownPropertyPaths; + oldKnownPropertyPaths = this.knownPropertyPaths; + this.unknownPropertyPaths = {}; + this.knownPropertyPaths = {}; + } + var error = this.validateAll(data, schema.not, null, null, dataPointerPath); + var notErrors = this.errors.slice(oldErrorCount); + this.errors = this.errors.slice(0, oldErrorCount); + if (this.trackUnknownProperties) { + this.unknownPropertyPaths = oldUnknownPropertyPaths; + this.knownPropertyPaths = oldKnownPropertyPaths; + } + if (error === null && notErrors.length === 0) { + return this.createError(ErrorCodes.NOT_PASSED, {}, "", "/not", null, data, schema); + } + return null; +}; + +ValidatorContext.prototype.validateHypermedia = function validateCombinations(data, schema, dataPointerPath) { + if (!schema.links) { + return null; + } + var error; + for (var i = 0; i < schema.links.length; i++) { + var ldo = schema.links[i]; + if (ldo.rel === "describedby") { + var template = new UriTemplate(ldo.href); + var allPresent = true; + for (var j = 0; j < template.varNames.length; j++) { + if (!(template.varNames[j] in data)) { + allPresent = false; + break; + } + } + if (allPresent) { + var schemaUrl = template.fillFromObject(data); + var subSchema = {"$ref": schemaUrl}; + if (error = this.validateAll(data, subSchema, [], ["links", i], dataPointerPath)) { + return error; + } + } + } + } +}; + +// parseURI() and resolveUrl() are from https://gist.github.com/1088850 +// - released as public domain by author ("Yaffle") - see comments on gist + +function parseURI(url) { + var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); + // authority = '//' + user + ':' + pass '@' + hostname + ':' port + return (m ? { + href : m[0] || '', + protocol : m[1] || '', + authority: m[2] || '', + host : m[3] || '', + hostname : m[4] || '', + port : m[5] || '', + pathname : m[6] || '', + search : m[7] || '', + hash : m[8] || '' + } : null); +} + +function resolveUrl(base, href) {// RFC 3986 + + function removeDotSegments(input) { + var output = []; + input.replace(/^(\.\.?(\/|$))+/, '') + .replace(/\/(\.(\/|$))+/g, '/') + .replace(/\/\.\.$/, '/../') + .replace(/\/?[^\/]*/g, function (p) { + if (p === '/..') { + output.pop(); + } else { + output.push(p); + } + }); + return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : ''); + } + + href = parseURI(href || ''); + base = parseURI(base || ''); + + return !href || !base ? null : (href.protocol || base.protocol) + + (href.protocol || href.authority ? href.authority : base.authority) + + removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) + + (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + + href.hash; +} + +function getDocumentUri(uri) { + return uri.split('#')[0]; +} +function normSchema(schema, baseUri) { + if (schema && typeof schema === "object") { + if (baseUri === undefined) { + baseUri = schema.id; + } else if (typeof schema.id === "string") { + baseUri = resolveUrl(baseUri, schema.id); + schema.id = baseUri; + } + if (Array.isArray(schema)) { + for (var i = 0; i < schema.length; i++) { + normSchema(schema[i], baseUri); + } + } else { + if (typeof schema['$ref'] === "string") { + schema['$ref'] = resolveUrl(baseUri, schema['$ref']); + } + for (var key in schema) { + if (key !== "enum") { + normSchema(schema[key], baseUri); + } + } + } + } +} + +function defaultErrorReporter(language) { + language = language || 'en'; + + var errorMessages = languages[language]; + + return function (error) { + var messageTemplate = errorMessages[error.code] || ErrorMessagesDefault[error.code]; + if (typeof messageTemplate !== 'string') { + return "Unknown error code " + error.code + ": " + JSON.stringify(error.messageParams); + } + var messageParams = error.params; + // Adapted from Crockford's supplant() + return messageTemplate.replace(/\{([^{}]*)\}/g, function (whole, varName) { + var subValue = messageParams[varName]; + return typeof subValue === 'string' || typeof subValue === 'number' ? subValue : whole; + }); + }; +} + +var ErrorCodes = { + INVALID_TYPE: 0, + ENUM_MISMATCH: 1, + ANY_OF_MISSING: 10, + ONE_OF_MISSING: 11, + ONE_OF_MULTIPLE: 12, + NOT_PASSED: 13, + // Numeric errors + NUMBER_MULTIPLE_OF: 100, + NUMBER_MINIMUM: 101, + NUMBER_MINIMUM_EXCLUSIVE: 102, + NUMBER_MAXIMUM: 103, + NUMBER_MAXIMUM_EXCLUSIVE: 104, + NUMBER_NOT_A_NUMBER: 105, + // String errors + STRING_LENGTH_SHORT: 200, + STRING_LENGTH_LONG: 201, + STRING_PATTERN: 202, + // Object errors + OBJECT_PROPERTIES_MINIMUM: 300, + OBJECT_PROPERTIES_MAXIMUM: 301, + OBJECT_REQUIRED: 302, + OBJECT_ADDITIONAL_PROPERTIES: 303, + OBJECT_DEPENDENCY_KEY: 304, + // Array errors + ARRAY_LENGTH_SHORT: 400, + ARRAY_LENGTH_LONG: 401, + ARRAY_UNIQUE: 402, + ARRAY_ADDITIONAL_ITEMS: 403, + // Custom/user-defined errors + FORMAT_CUSTOM: 500, + KEYWORD_CUSTOM: 501, + // Schema structure + CIRCULAR_REFERENCE: 600, + // Non-standard validation options + UNKNOWN_PROPERTY: 1000 +}; +var ErrorCodeLookup = {}; +for (var key in ErrorCodes) { + ErrorCodeLookup[ErrorCodes[key]] = key; +} +var ErrorMessagesDefault = { + INVALID_TYPE: "Invalid type: {type} (expected {expected})", + ENUM_MISMATCH: "No enum match for: {value}", + ANY_OF_MISSING: "Data does not match any schemas from \"anyOf\"", + ONE_OF_MISSING: "Data does not match any schemas from \"oneOf\"", + ONE_OF_MULTIPLE: "Data is valid against more than one schema from \"oneOf\": indices {index1} and {index2}", + NOT_PASSED: "Data matches schema from \"not\"", + // Numeric errors + NUMBER_MULTIPLE_OF: "Value {value} is not a multiple of {multipleOf}", + NUMBER_MINIMUM: "Value {value} is less than minimum {minimum}", + NUMBER_MINIMUM_EXCLUSIVE: "Value {value} is equal to exclusive minimum {minimum}", + NUMBER_MAXIMUM: "Value {value} is greater than maximum {maximum}", + NUMBER_MAXIMUM_EXCLUSIVE: "Value {value} is equal to exclusive maximum {maximum}", + NUMBER_NOT_A_NUMBER: "Value {value} is not a valid number", + // String errors + STRING_LENGTH_SHORT: "String is too short ({length} chars), minimum {minimum}", + STRING_LENGTH_LONG: "String is too long ({length} chars), maximum {maximum}", + STRING_PATTERN: "String does not match pattern: {pattern}", + // Object errors + OBJECT_PROPERTIES_MINIMUM: "Too few properties defined ({propertyCount}), minimum {minimum}", + OBJECT_PROPERTIES_MAXIMUM: "Too many properties defined ({propertyCount}), maximum {maximum}", + OBJECT_REQUIRED: "Missing required property: {key}", + OBJECT_ADDITIONAL_PROPERTIES: "Additional properties not allowed", + OBJECT_DEPENDENCY_KEY: "Dependency failed - key must exist: {missing} (due to key: {key})", + // Array errors + ARRAY_LENGTH_SHORT: "Array is too short ({length}), minimum {minimum}", + ARRAY_LENGTH_LONG: "Array is too long ({length}), maximum {maximum}", + ARRAY_UNIQUE: "Array items are not unique (indices {match1} and {match2})", + ARRAY_ADDITIONAL_ITEMS: "Additional items not allowed", + // Format errors + FORMAT_CUSTOM: "Format validation failed ({message})", + KEYWORD_CUSTOM: "Keyword failed: {key} ({message})", + // Schema structure + CIRCULAR_REFERENCE: "Circular $refs: {urls}", + // Non-standard validation options + UNKNOWN_PROPERTY: "Unknown property (not in schema)" +}; + +function ValidationError(code, params, dataPath, schemaPath, subErrors) { + Error.call(this); + if (code === undefined) { + throw new Error ("No error code supplied: " + schemaPath); + } + this.message = ''; + this.params = params; + this.code = code; + this.dataPath = dataPath || ""; + this.schemaPath = schemaPath || ""; + this.subErrors = subErrors || null; + + var err = new Error(this.message); + this.stack = err.stack || err.stacktrace; + if (!this.stack) { + try { + throw err; + } + catch(err) { + this.stack = err.stack || err.stacktrace; + } + } +} +ValidationError.prototype = Object.create(Error.prototype); +ValidationError.prototype.constructor = ValidationError; +ValidationError.prototype.name = 'ValidationError'; + +ValidationError.prototype.prefixWith = function (dataPrefix, schemaPrefix) { + if (dataPrefix !== null) { + dataPrefix = dataPrefix.replace(/~/g, "~0").replace(/\//g, "~1"); + this.dataPath = "/" + dataPrefix + this.dataPath; + } + if (schemaPrefix !== null) { + schemaPrefix = schemaPrefix.replace(/~/g, "~0").replace(/\//g, "~1"); + this.schemaPath = "/" + schemaPrefix + this.schemaPath; + } + if (this.subErrors !== null) { + for (var i = 0; i < this.subErrors.length; i++) { + this.subErrors[i].prefixWith(dataPrefix, schemaPrefix); + } + } + return this; +}; + +function isTrustedUrl(baseUrl, testUrl) { + if(testUrl.substring(0, baseUrl.length) === baseUrl){ + var remainder = testUrl.substring(baseUrl.length); + if ((testUrl.length > 0 && testUrl.charAt(baseUrl.length - 1) === "/") + || remainder.charAt(0) === "#" + || remainder.charAt(0) === "?") { + return true; + } + } + return false; +} + +var languages = {}; +function createApi(language) { + var globalContext = new ValidatorContext(); + var currentLanguage; + var customErrorReporter; + var api = { + setErrorReporter: function (reporter) { + if (typeof reporter === 'string') { + return this.language(reporter); + } + customErrorReporter = reporter; + return true; + }, + addFormat: function () { + globalContext.addFormat.apply(globalContext, arguments); + }, + language: function (code) { + if (!code) { + return currentLanguage; + } + if (!languages[code]) { + code = code.split('-')[0]; // fall back to base language + } + if (languages[code]) { + currentLanguage = code; + return code; // so you can tell if fall-back has happened + } + return false; + }, + addLanguage: function (code, messageMap) { + var key; + for (key in ErrorCodes) { + if (messageMap[key] && !messageMap[ErrorCodes[key]]) { + messageMap[ErrorCodes[key]] = messageMap[key]; + } + } + var rootCode = code.split('-')[0]; + if (!languages[rootCode]) { // use for base language if not yet defined + languages[code] = messageMap; + languages[rootCode] = messageMap; + } else { + languages[code] = Object.create(languages[rootCode]); + for (key in messageMap) { + if (typeof languages[rootCode][key] === 'undefined') { + languages[rootCode][key] = messageMap[key]; + } + languages[code][key] = messageMap[key]; + } + } + return this; + }, + freshApi: function (language) { + var result = createApi(); + if (language) { + result.language(language); + } + return result; + }, + validate: function (data, schema, checkRecursive, banUnknownProperties) { + var def = defaultErrorReporter(currentLanguage); + var errorReporter = customErrorReporter ? function (error, data, schema) { + return customErrorReporter(error, data, schema) || def(error, data, schema); + } : def; + var context = new ValidatorContext(globalContext, false, errorReporter, checkRecursive, banUnknownProperties); + if (typeof schema === "string") { + schema = {"$ref": schema}; + } + context.addSchema("", schema); + var error = context.validateAll(data, schema, null, null, ""); + if (!error && banUnknownProperties) { + error = context.banUnknownProperties(data, schema); + } + this.error = error; + this.missing = context.missing; + this.valid = (error === null); + return this.valid; + }, + validateResult: function () { + var result = {toString: function () { + return this.valid ? 'valid' : this.error.message; + }}; + this.validate.apply(result, arguments); + return result; + }, + validateMultiple: function (data, schema, checkRecursive, banUnknownProperties) { + var def = defaultErrorReporter(currentLanguage); + var errorReporter = customErrorReporter ? function (error, data, schema) { + return customErrorReporter(error, data, schema) || def(error, data, schema); + } : def; + var context = new ValidatorContext(globalContext, true, errorReporter, checkRecursive, banUnknownProperties); + if (typeof schema === "string") { + schema = {"$ref": schema}; + } + context.addSchema("", schema); + context.validateAll(data, schema, null, null, ""); + if (banUnknownProperties) { + context.banUnknownProperties(data, schema); + } + var result = {toString: function () { + return this.valid ? 'valid' : this.error.message; + }}; + result.errors = context.errors; + result.missing = context.missing; + result.valid = (result.errors.length === 0); + return result; + }, + addSchema: function () { + return globalContext.addSchema.apply(globalContext, arguments); + }, + getSchema: function () { + return globalContext.getSchema.apply(globalContext, arguments); + }, + getSchemaMap: function () { + return globalContext.getSchemaMap.apply(globalContext, arguments); + }, + getSchemaUris: function () { + return globalContext.getSchemaUris.apply(globalContext, arguments); + }, + getMissingUris: function () { + return globalContext.getMissingUris.apply(globalContext, arguments); + }, + dropSchemas: function () { + globalContext.dropSchemas.apply(globalContext, arguments); + }, + defineKeyword: function () { + globalContext.defineKeyword.apply(globalContext, arguments); + }, + defineError: function (codeName, codeNumber, defaultMessage) { + if (typeof codeName !== 'string' || !/^[A-Z]+(_[A-Z]+)*$/.test(codeName)) { + throw new Error('Code name must be a string in UPPER_CASE_WITH_UNDERSCORES'); + } + if (typeof codeNumber !== 'number' || codeNumber%1 !== 0 || codeNumber < 10000) { + throw new Error('Code number must be an integer > 10000'); + } + if (typeof ErrorCodes[codeName] !== 'undefined') { + throw new Error('Error already defined: ' + codeName + ' as ' + ErrorCodes[codeName]); + } + if (typeof ErrorCodeLookup[codeNumber] !== 'undefined') { + throw new Error('Error code already used: ' + ErrorCodeLookup[codeNumber] + ' as ' + codeNumber); + } + ErrorCodes[codeName] = codeNumber; + ErrorCodeLookup[codeNumber] = codeName; + ErrorMessagesDefault[codeName] = ErrorMessagesDefault[codeNumber] = defaultMessage; + for (var langCode in languages) { + var language = languages[langCode]; + if (language[codeName]) { + language[codeNumber] = language[codeNumber] || language[codeName]; + } + } + }, + reset: function () { + globalContext.reset(); + this.error = null; + this.missing = []; + this.valid = true; + }, + missing: [], + error: null, + valid: true, + normSchema: normSchema, + resolveUrl: resolveUrl, + getDocumentUri: getDocumentUri, + errorCodes: ErrorCodes + }; + api.language(language || 'en'); + return api; +} + +var tv4 = createApi(); +tv4.addLanguage('en-gb', ErrorMessagesDefault); + +//legacy property +tv4.tv4 = tv4; + +return tv4; // used by _header.js to globalise. + +})); + +/***/ }), + +/***/ "./node_modules/webfinger.js/src/webfinger.js": +/*!****************************************************!*\ + !*** ./node_modules/webfinger.js/src/webfinger.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* global define */ /*! * webfinger.js * http://github.com/silverbucket/webfinger.js @@ -24,5 +3883,8387 @@ t.read=function(e,t,r,o,n){var i,s,a=8*n-o-1,u=(1<>1,h=-7,l=r?n-1:0,d= * You are free to use, modify and distribute this software, but all copyright * information must remain. * - */"function"!=typeof fetch&&"function"!=typeof XMLHttpRequest&&(XMLHttpRequest=r(29)),function(r){var n={"http://webfist.org/spec/rel":"webfist","http://webfinger.net/rel/avatar":"avatar",remotestorage:"remotestorage","http://tools.ietf.org/id/draft-dejong-remotestorage":"remotestorage",remoteStorage:"remotestorage","http://www.packetizer.com/rel/share":"share","http://webfinger.net/rel/profile-page":"profile",me:"profile",vcard:"vcard",blog:"blog","http://packetizer.com/rel/blog":"blog","http://schemas.google.com/g/2010#updates-from":"updates","https://camlistore.org/rel/server":"camilstore"},i={avatar:[],remotestorage:[],blog:[],vcard:[],updates:[],share:[],profile:[],webfist:[],camlistore:[]},s=["webfinger","host-meta","host-meta.json"];function a(e){return e.toString=function(){return this.message},e}function u(e){"object"!=typeof e&&(e={}),this.config={tls_only:void 0===e.tls_only||e.tls_only,webfist_fallback:void 0!==e.webfist_fallback&&e.webfist_fallback,uri_fallback:void 0!==e.uri_fallback&&e.uri_fallback,request_timeout:void 0!==e.request_timeout?e.request_timeout:1e4}}u.prototype.__fetchJRD=function(e,t,r){if("function"==typeof fetch)return this.__fetchJRD_fetch(e,t,r);if("function"==typeof XMLHttpRequest)return this.__fetchJRD_XHR(e,t,r);throw new Error("add a polyfill for fetch or XMLHttpRequest")},u.prototype.__fetchJRD_fetch=function(e,t,r){var o,n=this;"function"==typeof AbortController&&(o=new AbortController);var i=fetch(e,{headers:{Accept:"application/jrd+json, application/json"},signal:o?o.signal:void 0}).then((function(t){if(t.ok)return t.text();throw 404===t.status?a({message:"resource not found",url:e,status:t.status}):a({message:"error during request",url:e,status:t.status})}),(function(t){throw a({message:"error during request",url:e,status:void 0,err:t})})).then((function(t){if(n.__isValidJSON(t))return t;throw a({message:"invalid json",url:e,status:void 0})})),s=new Promise((function(t,r){setTimeout((function(){r(a({message:"request timed out",url:e,status:void 0})),o&&o.abort()}),n.config.request_timeout)}));Promise.race([i,s]).then((function(e){r(e)})).catch((function(e){t(e)}))},u.prototype.__fetchJRD_XHR=function(e,t,r){var o=this,n=!1,i=new XMLHttpRequest;function s(){if(!n){if(n=!0,200===i.status)return o.__isValidJSON(i.responseText)?r(i.responseText):t(a({message:"invalid json",url:e,status:i.status}));if(404===i.status)return t(a({message:"resource not found",url:e,status:i.status}));if(i.status>=301&&i.status<=302){var s=i.getResponseHeader("Location");return function(e){return"string"==typeof e&&"https"===e.split("://")[0]}(s)?u():t(a({message:"no redirect URL found",url:e,status:i.status}))}return t(a({message:"error during request",url:e,status:i.status}))}}function u(){i.onreadystatechange=function(){4===i.readyState&&s()},i.onload=function(){s()},i.ontimeout=function(){return t(a({message:"request timed out",url:e,status:i.status}))},i.open("GET",e,!0),i.timeout=o.config.request_timeout,i.setRequestHeader("Accept","application/jrd+json, application/json"),i.send()}return u()},u.prototype.__isValidJSON=function(e){try{JSON.parse(e)}catch(e){return!1}return!0},u.prototype.__isLocalhost=function(e){return/^localhost(\.localdomain)?(\:[0-9]+)?$/.test(e)},u.prototype.__processJRD=function(e,t,r,o){var s=JSON.parse(t);if("object"!=typeof s||"object"!=typeof s.links)return void 0!==s.error?r(a({message:s.error,request:e})):r(a({message:"unknown response from server",request:e}));var u=s.links;Array.isArray(u)||(u=[]);var c={object:s,json:t,idx:{}};c.idx.properties={name:void 0},c.idx.links=JSON.parse(JSON.stringify(i)),u.map((function(e,t){if(n.hasOwnProperty(e.rel)&&c.idx.links[n[e.rel]]){var r={};Object.keys(e).map((function(t,o){r[t]=e[t]})),c.idx.links[n[e.rel]].push(r)}}));var h=JSON.parse(t).properties;for(var l in h)h.hasOwnProperty(l)&&"http://packetizer.com/ns/name"===l&&(c.idx.properties.name=h[l]);return o(c)},u.prototype.lookup=function(e,t){if("string"!=typeof e)throw new Error("first parameter must be a user address");if("function"!=typeof t)throw new Error("second parameter must be a callback");var r=this,o="";o=e.indexOf("://")>-1?e.replace(/ /g,"").split("/")[2]:e.replace(/ /g,"").split("@")[1];var n=0,i="https";function a(){var t="";return e.split("://")[1]||(t="acct:"),i+"://"+o+"/.well-known/"+s[n]+"?resource="+t+e}function u(e){if(r.config.uri_fallback&&"webfist.org"!==o&&n!==s.length-1)return n+=1,c();if(!r.config.tls_only&&"https"===i)return n=0,i="http",c();if(!r.config.webfist_fallback||"webfist.org"===o)return t(e);n=0,i="http",o="webfist.org";var u=a();r.__fetchJRD(u,t,(function(e){r.__processJRD(u,e,t,(function(e){"object"==typeof e.idx.links.webfist&&"string"==typeof e.idx.links.webfist[0].href&&r.__fetchJRD(e.idx.links.webfist[0].href,t,(function(e){r.__processJRD(u,e,t,(function(e){return t(null,t)}))}))}))}))}function c(){var e=a();r.__fetchJRD(e,u,(function(o){r.__processJRD(e,o,t,(function(e){t(null,e)}))}))}return r.__isLocalhost(o)&&(i="http"),setTimeout(c,0)},u.prototype.lookupLink=function(e,t,r){if(!i.hasOwnProperty(t))return r("unsupported rel "+t);this.lookup(e,(function(e,o){var n=o.idx.links[t];return e?r(e):0===n.length?r('no links found with rel="'+t+'"'):r(null,n[0])}))},void 0===(o=function(){return u}.apply(t,[]))||(e.exports=o)}()},function(e,t){e.exports=XMLHttpRequest},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=o(r(3)),i=o(r(17)),s=o(r(1)),a=r(0),u=o(r(31)),c=o(r(12)),h=o(r(4)),l=o(r(16)),d=o(r(8)),f=o(r(14)),p=o(r(15)),m=o(r(32)),g=o(r(33)),y=o(r(13)),v=o(r(34)),_=o(r(35)),b=o(r(36)),w={features:[],featuresDone:0,readyFired:!1,loadFeatures(){this.features=[],this.featuresDone=0,this.readyFired=!1,this.featureModules={WireClient:m.default,Dropbox:p.default,GoogleDrive:f.default,Access:c.default,Discover:l.default,Authorize:h.default,BaseClient:d.default,Env:i.default},n.default.cache&&(0,a.extend)(this.featureModules,{Caching:y.default,IndexedDB:v.default,LocalStorage:_.default,InMemoryStorage:b.default,Sync:g.default}),n.default.disableFeatures.forEach(e=>{this.featureModules[e]&&delete this.featureModules[e]}),this._allLoaded=!1;for(const e in this.featureModules)this.loadFeature(e)},hasFeature(e){for(let t=this.features.length-1;t>=0;t--)if(this.features[t].name===e)return this.features[t].supported;return!1},loadFeature(e){const t=this.featureModules[e],r=!t._rs_supported||t._rs_supported();(0,s.default)(`[RemoteStorage] [FEATURE ${e}] initializing ...`),"object"==typeof r?r.then(()=>{this.featureSupported(e,!0),this.initFeature(e)},()=>{this.featureSupported(e,!1)}):"boolean"==typeof r?(this.featureSupported(e,r),r&&this.initFeature(e)):this.featureSupported(e,!1)},initFeature(e){const t=this.featureModules[e];let r;try{r=t._rs_init(this)}catch(t){return void this.featureFailed(e,t)}"object"==typeof r&&"function"==typeof r.then?r.then(()=>{this.featureInitialized(e)},t=>{this.featureFailed(e,t)}):this.featureInitialized(e)},featureFailed(e,t){(0,s.default)(`[RemoteStorage] [FEATURE ${e}] initialization failed (${t})`),this.featureDone()},featureSupported(e,t){(0,s.default)(`[RemoteStorage] [FEATURE ${e}]${t?"":"not "} supported`),t||this.featureDone()},featureInitialized(e){(0,s.default)(`[RemoteStorage] [FEATURE ${e}] initialized`),this.features.push({name:e,init:this.featureModules[e]._rs_init,supported:!0,cleanup:this.featureModules[e]._rs_cleanup}),this.featureDone()},featureDone(){this.featuresDone++,this.featuresDone===Object.keys(this.featureModules).length&&setTimeout(this.featuresLoaded.bind(this),0)},_setCachingModule(){["IndexedDB","LocalStorage","InMemoryStorage"].some(e=>{if(this.features.some(t=>t.name===e))return this.features.local=this.featureModules[e],!0})},_fireReady(){try{this.readyFired||(this._emit("ready"),this.readyFired=!0)}catch(e){console.error("'ready' failed: ",e,e.stack),this._emit("error",e)}},featuresLoaded(){(0,s.default)("[RemoteStorage] All features loaded"),this._setCachingModule(),this.local=n.default.cache&&this.features.local&&new this.features.local,this.local&&this.remote?(this._setGPD(u.default,this),this._bindChange(this.local)):this.remote&&this._setGPD(this.remote,this.remote),this.remote&&(this.remote.on("connected",()=>{this._fireReady(),this._emit("connected")}),this.remote.on("not-connected",()=>{this._fireReady(),this._emit("not-connected")}),this.remote.connected&&(this._fireReady(),this._emit("connected")),this.hasFeature("Authorize")||this.remote.stopWaitingForToken()),this._collectCleanupFunctions();try{this._allLoaded=!0,this._emit("features-loaded")}catch(e){(0,a.logError)(e),this._emit("error",e)}this._processPending()},_collectCleanupFunctions(){this._cleanups=[];for(let e=0;e(this._emit("wire-done",{success:!0}),Promise.resolve(e)),e=>(this._emit("wire-done",{success:!1}),Promise.reject(e)))}))}};e.exports=s},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(4)),s=n(r(2)),a=n(r(5)),u=n(r(1)),c=r(0),h=r(7),l=r(9);let d;const f="remotestorage:wireclient",p={"draft-dejong-remotestorage-00":2,"draft-dejong-remotestorage-01":3,"draft-dejong-remotestorage-02":4,"https://www.w3.org/community/rww/wiki/read-write-web-00#simple":1};class m extends l.RemoteBase{constructor(e){if(super(e),this._revisionCache={},d=(0,c.localStorageAvailable)(),this.addEvents(["connected","not-connected"]),d){const e=function(){const e=(0,c.getJSONFromLocalStorage)(f)||{},{userAddress:t,href:r,storageApi:o,token:n,properties:i}=e;return{userAddress:t,href:r,storageApi:o,token:n,properties:i}}();e&&setTimeout(()=>{this.configure(e)},0)}this.connected&&setTimeout(this._emit.bind(this),0,"connected")}get storageType(){if(this.storageApi){const e=this.storageApi.match(/draft-dejong-(remotestorage-\d\d)/);return e?e[1]:"2012.04"}}_request(e,t,r,n,s,l,d){return o(this,void 0,void 0,(function*(){if(this.isForbiddenRequestMethod(e,t))return Promise.reject(`Don't use ${e} on directories!`);let o;return r!==i.default.IMPLIED_FAKE_TOKEN&&(n.Authorization="Bearer "+r),this.rs._emit("wire-busy",{method:e,isFolder:(0,c.isFolder)(t)}),(0,h.requestWithTimeout)(e,t,{body:s,headers:n,responseType:"arraybuffer"}).then(r=>{if(this.online||(this.online=!0,this.rs._emit("network-online")),this.rs._emit("wire-done",{method:e,isFolder:(0,c.isFolder)(t),success:!0}),n=r.status,[401,403,404,412].indexOf(n)>=0)return(0,u.default)("[WireClient] Error response status",r.status),o=l?this.stripQuotes(r.getResponseHeader("ETag")):void 0,401===r.status&&this.rs._emit("error",new a.default),Promise.resolve({statusCode:r.status,revision:o});if(function(e){return[201,204,304].indexOf(e)>=0}(r.status)||200===r.status&&"GET"!==e)return o=this.stripQuotes(r.getResponseHeader("ETag")),(0,u.default)("[WireClient] Successful request",o),Promise.resolve({statusCode:r.status,revision:o});{const e=r.getResponseHeader("Content-Type");o=l?this.stripQuotes(r.getResponseHeader("ETag")):200===r.status?d:void 0;const t=function(e){let t,r="utf-8";return e&&(t=e.match(/charset=(.+)$/),t&&(r=t[1])),r}(e);return(0,c.shouldBeTreatedAsBinary)(r.response,e)?((0,u.default)("[WireClient] Successful request with unknown or binary mime-type",o),Promise.resolve({statusCode:r.status,body:r.response,contentType:e,revision:o})):(0,c.getTextFromArrayBuffer)(r.response,t).then(t=>((0,u.default)("[WireClient] Successful request",o),Promise.resolve({statusCode:r.status,body:t,contentType:e,revision:o})))}var n},r=>(this.online&&(this.online=!1,this.rs._emit("network-offline")),this.rs._emit("wire-done",{method:e,isFolder:(0,c.isFolder)(t),success:!1}),Promise.reject(r)))}))}configure(e){if("object"!=typeof e)throw new Error("WireClient configure settings parameter should be an object");if(void 0!==e.userAddress&&(this.userAddress=e.userAddress),void 0!==e.href&&(this.href=e.href),void 0!==e.storageApi&&(this.storageApi=e.storageApi),void 0!==e.token&&(this.token=e.token),void 0!==e.properties&&(this.properties=e.properties),"string"==typeof this.storageApi){const e=p[this.storageApi]||5;this.supportsRevs=e>=2}this.href&&this.token?(this.connected=!0,this.online=!0,this._emit("connected")):this.connected=!1,d&&(localStorage[f]=JSON.stringify({userAddress:this.userAddress,href:this.href,storageApi:this.storageApi,token:this.token,properties:this.properties}))}get(e,t={}){if(!this.connected)return Promise.reject("not connected (path: "+e+")");const r={};return this.supportsRevs&&t.ifNoneMatch&&(r["If-None-Match"]=this.addQuotes(t.ifNoneMatch)),this._request("GET",this.href+(0,c.cleanPath)(e),this.token,r,void 0,this.supportsRevs,this._revisionCache[e]).then(t=>{if(!(0,c.isFolder)(e))return Promise.resolve(t);let r={};if(void 0!==t.body)try{t.body=JSON.parse(t.body)}catch(t){return Promise.reject("Folder description at "+this.href+(0,c.cleanPath)(e)+" is not JSON")}if(200===t.statusCode&&"object"==typeof t.body){if(0===Object.keys(t.body).length)t.statusCode=404;else if("http://remotestorage.io/spec/folder-description"===(o=t.body)["@context"]&&"object"==typeof o.items){for(const r in t.body.items)this._revisionCache[e+r]=t.body.items[r].ETag;r=t.body.items}else Object.keys(t.body).forEach(o=>{this._revisionCache[e+o]=t.body[o],r[o]={ETag:t.body[o]}});return t.body=r,Promise.resolve(t)}return Promise.resolve(t);var o})}put(e,t,r,o={}){if(!this.connected)return Promise.reject("not connected (path: "+e+")");!r.match(/charset=/)&&(t instanceof ArrayBuffer||(0,h.isArrayBufferView)(t))&&(r+="; charset=binary");const n={"Content-Type":r};return this.supportsRevs&&(o.ifMatch&&(n["If-Match"]=this.addQuotes(o.ifMatch)),o.ifNoneMatch&&(n["If-None-Match"]=this.addQuotes(o.ifNoneMatch))),this._request("PUT",this.href+(0,c.cleanPath)(e),this.token,n,t,this.supportsRevs)}delete(e,t={}){if(!this.connected)throw new Error("not connected (path: "+e+")");t||(t={});const r={};return this.supportsRevs&&t.ifMatch&&(r["If-Match"]=this.addQuotes(t.ifMatch)),this._request("DELETE",this.href+(0,c.cleanPath)(e),this.token,r,void 0,this.supportsRevs)}static _rs_init(e){e.remote=new m(e),e.remote.online=!0}static _rs_supported(){return"function"==typeof fetch||"function"==typeof XMLHttpRequest}static _rs_cleanup(){d&&delete localStorage[f]}}(0,c.applyMixins)(m,[s.default]),e.exports=m},function(e,t,r){"use strict";var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(3)),s=n(r(17)),a=n(r(2)),u=n(r(1)),c=n(r(4)),h=n(r(10)),l=n(r(5)),d=r(0);let f,p;function m(e,t,r){return{action:e,path:t,promise:r}}function g(e,t){return e.common.revision!==t&&(!e.remote||e.remote.revision!==t)}function y(e){return e.common&&e.common.revision}class v{constructor(e){this.rs=e,this._tasks={},this._running={},this._timeStarted={},this.numThreads=10,this.rs.local.onDiff(e=>{this.addTask(e),this.doTasks()}),this.rs.caching.onActivate(e=>{this.addTask(e),this.doTasks()}),this.addEvents(["done","req-done"])}now(){return(new Date).getTime()}queueGetRequest(e){return new Promise((t,r)=>{this.rs.remote.connected?this.rs.remote.online?(this.addTask(e,function(){this.rs.local.get(e).then(e=>t(e))}.bind(this)),this.doTasks()):r("cannot fulfill maxAge requirement - remote is not online"):r("cannot fulfill maxAge requirement - remote is not connected")})}corruptServerItemsMap(e,t){if("object"!=typeof e||Array.isArray(e))return!0;for(const r in e){const o=e[r];if("object"!=typeof o)return!0;if("string"!=typeof o.ETag)return!0;if((0,d.isFolder)(r)){if(-1!==r.substring(0,r.length-1).indexOf("/"))return!0}else{if(-1!==r.indexOf("/"))return!0;if(t){if("string"!=typeof o["Content-Type"])return!0;if("number"!=typeof o["Content-Length"])return!0}}}return!1}corruptItemsMap(e){if("object"!=typeof e||Array.isArray(e))return!0;for(const t in e)if("boolean"!=typeof e[t])return!0;return!1}corruptRevision(e){return"object"!=typeof e||Array.isArray(e)||e.revision&&"string"!=typeof e.revision||e.body&&"string"!=typeof e.body&&"object"!=typeof e.body||e.contentType&&"string"!=typeof e.contentType||e.contentLength&&"number"!=typeof e.contentLength||e.timestamp&&"number"!=typeof e.timestamp||e.itemsMap&&this.corruptItemsMap(e.itemsMap)}isCorrupt(e){return"object"!=typeof e||Array.isArray(e)||"string"!=typeof e.path||this.corruptRevision(e.common)||e.local&&this.corruptRevision(e.local)||e.remote&&this.corruptRevision(e.remote)||e.push&&this.corruptRevision(e.push)}hasTasks(){return Object.getOwnPropertyNames(this._tasks).length>0}collectDiffTasks(){return o(this,void 0,void 0,(function*(){let e=0;return this.rs.local.forAllNodes(t=>{e>100||(this.isCorrupt(t)?((0,u.default)("[Sync] WARNING: corrupt node in local cache",t),"object"==typeof t&&t.path&&(this.addTask(t.path),e++)):(this.needsFetch(t)&&this.rs.access.checkPathPermission(t.path,"r")||(0,d.isDocument)(t.path)&&this.needsPush(t)&&this.rs.access.checkPathPermission(t.path,"rw"))&&(this.addTask(t.path),e++))}).then(()=>e).catch(e=>{throw e})}))}inConflict(e){return e.local&&e.remote&&(void 0!==e.remote.body||e.remote.itemsMap)}needsRefresh(e){return!!e.common&&(!e.common.timestamp||this.now()-e.common.timestamp>i.default.syncInterval)}needsFetch(e){return!!this.inConflict(e)||(!(!e.common||void 0!==e.common.itemsMap||void 0!==e.common.body)||!(!e.remote||void 0!==e.remote.itemsMap||void 0!==e.remote.body))}needsPush(e){return!this.inConflict(e)&&(!(!e.local||e.push)||void 0)}needsRemotePut(e){return e.local&&e.local.body}needsRemoteDelete(e){return e.local&&!1===e.local.body}getParentPath(e){const t=e.match(/^(.*\/)([^\/]+\/?)$/);if(t)return t[1];throw new Error('Not a valid path: "'+e+'"')}deleteChildPathsFromTasks(){for(const e in this._tasks){const t=(0,d.pathsFromRoot)(e);for(let r=1;r{let t;if(this.needsRefresh(e)){try{t=this.getParentPath(e.path)}catch(e){}t&&this.rs.access.checkPathPermission(t,"r")?this.addTask(t):this.rs.access.checkPathPermission(e.path,"r")&&this.addTask(e.path)}}).then(()=>this.deleteChildPathsFromTasks()).catch(e=>{throw e})}))}flush(e){for(const t in e)"FLUSH"===this.rs.caching.checkPath(t)&&e[t]&&!e[t].local&&((0,u.default)("[Sync] Flushing",t),e[t]=void 0);return e}doTask(e){return this.rs.local.getNodes([e]).then(t=>{const r=t[e];return void 0===r||function(e){return e.remote&&e.remote.revision&&!e.remote.itemsMap&&!e.remote.body}(r)?m("get",e,this.rs.remote.get(e)):this.needsRemotePut(r)?(r.push=(0,d.deepClone)(r.local),r.push.timestamp=this.now(),this.rs.local.setNodes(this.flush(t)).then(()=>{let t;return t=y(r)?{ifMatch:r.common.revision}:{ifNoneMatch:"*"},m("put",e,this.rs.remote.put(e,r.push.body,r.push.contentType,t))})):this.needsRemoteDelete(r)?(r.push={body:!1,timestamp:this.now()},this.rs.local.setNodes(this.flush(t)).then(()=>y(r)?m("delete",e,this.rs.remote.delete(e,{ifMatch:r.common.revision})):m("get",e,this.rs.remote.get(e)))):y(r)?m("get",e,this.rs.remote.get(e,{ifNoneMatch:r.common.revision})):m("get",e,this.rs.remote.get(e))})}autoMergeFolder(e){if(e.remote.itemsMap&&(e.common=e.remote,delete e.remote,e.common.itemsMap)){for(const t in e.common.itemsMap)e.local.itemsMap[t]||(e.local.itemsMap[t]=!1);(0,d.equal)(e.local.itemsMap,e.common.itemsMap)&&delete e.local}return e}autoMergeDocument(e){return!function(e){return(!e.remote||!e.remote.revision||e.remote.revision===e.common.revision)&&(void 0===e.common.body&&!1===e.remote.body||e.remote.body===e.common.body&&e.remote.contentType===e.common.contentType)}(e)?void 0!==e.remote.body&&((0,u.default)("[Sync] Emitting keep/revert"),this.rs.local._emitChange({origin:"conflict",path:e.path,oldValue:e.local.body,newValue:e.remote.body,lastCommonValue:e.common.body,oldContentType:e.local.contentType,newContentType:e.remote.contentType,lastCommonContentType:e.common.contentType}),e.remote.body?e.common=e.remote:e.common={},delete e.remote,delete e.local):delete(e=function(e){return e.remote&&!1===e.remote.body&&e.local&&!1===e.local.body&&delete e.local,e}(e)).remote,e}autoMerge(e){if(e.remote){if(e.local)return(0,d.isFolder)(e.path)?this.autoMergeFolder(e):this.autoMergeDocument(e);if((0,d.isFolder)(e.path))void 0!==e.remote.itemsMap&&(e.common=e.remote,delete e.remote);else if(void 0!==e.remote.body){const t={origin:"remote",path:e.path,oldValue:!1===e.common.body?void 0:e.common.body,newValue:!1===e.remote.body?void 0:e.remote.body,oldContentType:e.common.contentType,newContentType:e.remote.contentType};if((t.oldValue||t.newValue)&&this.rs.local._emitChange(t),!e.remote.body)return;e.common=e.remote,delete e.remote}return e}e.common.body&&this.rs.local._emitChange({origin:"remote",path:e.path,oldValue:e.common.body,newValue:void 0,oldContentType:e.common.contentType,newContentType:void 0})}updateCommonTimestamp(e,t){return o(this,void 0,void 0,(function*(){return this.rs.local.getNodes([e]).then(r=>(r[e]&&r[e].common&&r[e].common.revision===t&&(r[e].common.timestamp=this.now()),this.rs.local.setNodes(this.flush(r))))}))}markChildren(e,t,r,n){return o(this,void 0,void 0,(function*(){const o=[],i={},s={};for(const r in t)o.push(e+r),i[e+r]=t[r];for(const t in n)o.push(e+t);return this.rs.local.getNodes(o).then(t=>{let o,a;for(const u in t)if(a=t[u],i[u])a&&a.common?g(a,i[u].ETag)&&(r[u]=(0,d.deepClone)(a),r[u].remote={revision:i[u].ETag,timestamp:this.now()},r[u]=this.autoMerge(r[u])):(o=this.rs.caching.checkPath(u),"ALL"===o&&(r[u]={path:u,common:{timestamp:this.now()},remote:{revision:i[u].ETag,timestamp:this.now()}})),r[u]&&i[u]["Content-Type"]&&(r[u].remote.contentType=i[u]["Content-Type"]),r[u]&&i[u]["Content-Length"]&&(r[u].remote.contentLength=i[u]["Content-Length"]);else if(n[u.substring(e.length)]&&a&&a.common){if(a.common.itemsMap)for(const e in a.common.itemsMap)s[u+e]=!0;if(a.local&&a.local.itemsMap)for(const e in a.local.itemsMap)s[u+e]=!0;if(a.remote||(0,d.isFolder)(u))r[u]=void 0;else if(r[u]=this.autoMerge(a),void 0===r[u]){const t=this.getParentPath(u),o=r[t],n=u.substring(e.length);o&&o.local&&(delete o.local.itemsMap[n],(0,d.equal)(o.local.itemsMap,o.common.itemsMap)&&delete o.local)}}return this.deleteRemoteTrees(Object.keys(s),r).then(e=>this.rs.local.setNodes(this.flush(e)))})}))}deleteRemoteTrees(e,t){return o(this,void 0,void 0,(function*(){return 0===e.length?Promise.resolve(t):this.rs.local.getNodes(e).then(e=>o(this,void 0,void 0,(function*(){const r={};function o(e,t){if(e&&e.itemsMap)for(const o in e.itemsMap)r[t+o]=!0}for(const r in e){const n=e[r];n&&((0,d.isFolder)(r)?(o(n.common,r),o(n.local,r)):n.common&&void 0!==typeof n.common.body&&(t[r]=(0,d.deepClone)(n),t[r].remote={body:!1,timestamp:this.now()},t[r]=this.autoMerge(t[r])))}return this.deleteRemoteTrees(Object.keys(r),t).then(e=>this.rs.local.setNodes(this.flush(e)))})))}))}completeFetch(e,t,r,n){return o(this,void 0,void 0,(function*(){let o,i;const s=(0,d.pathsFromRoot)(e);return(0,d.isFolder)(e)?o=[e]:(i=s[1],o=[e,i]),this.rs.local.getNodes(o).then(o=>{let s,a,u=o[e];const c={};function h(e){if(e&&e.itemsMap)for(s in e.itemsMap)t[s]||(c[s]=!0)}if("object"==typeof u&&u.path===e&&"object"==typeof u.common||(u={path:e,common:{}},o[e]=u),u.remote={revision:n,timestamp:this.now()},(0,d.isFolder)(e))for(s in h(u.common),h(u.remote),u.remote.itemsMap={},t)u.remote.itemsMap[s]=!0;else u.remote.body=t,u.remote.contentType=r,a=o[i],a&&a.local&&a.local.itemsMap&&(s=e.substring(i.length),a.local.itemsMap[s]=!0,(0,d.equal)(a.local.itemsMap,a.common.itemsMap)&&delete a.local);return o[e]=this.autoMerge(u),{toBeSaved:o,missingChildren:c}})}))}completePush(e,t,r,n){return o(this,void 0,void 0,(function*(){return this.rs.local.getNodes([e]).then(o=>{const i=o[e];if(!i.push)throw this.stopped=!0,new Error("completePush called but no push version!");return r?((0,u.default)("[Sync] We have a conflict"),i.remote&&i.remote.revision===n||(i.remote={revision:n||"conflict",timestamp:this.now()},delete i.push),o[e]=this.autoMerge(i)):(i.common={revision:n,timestamp:this.now()},"put"===t?(i.common.body=i.push.body,i.common.contentType=i.push.contentType,(0,d.equal)(i.local.body,i.push.body)&&i.local.contentType===i.push.contentType&&delete i.local,delete i.push):"delete"===t&&(!1===i.local.body?o[e]=void 0:delete i.push)),this.rs.local.setNodes(this.flush(o))})}))}dealWithFailure(e){return o(this,void 0,void 0,(function*(){return this.rs.local.getNodes([e]).then(t=>{if(t[e])return delete t[e].push,this.rs.local.setNodes(this.flush(t))})}))}interpretStatus(e){const t={statusCode:e,successful:void 0,conflict:void 0,unAuth:void 0,notFound:void 0,changed:void 0,networkProblems:void 0};if("string"==typeof e&&("offline"===e||"timeout"===e))return t.successful=!1,t.networkProblems=!0,t;if("number"==typeof e){const r=Math.floor(e/100);return t.successful=2===r||304===e||412===e||404===e,t.conflict=412===e,t.unAuth=401===e&&this.rs.remote.token!==c.default.IMPLIED_FAKE_TOKEN||402===e||403===e,t.notFound=404===e,t.changed=304!==e,t}}handleGetResponse(e,t,r,n,i){return o(this,void 0,void 0,(function*(){return t.notFound&&(r=!!(0,d.isFolder)(e)&&{}),t.changed?this.completeFetch(e,r,n,i).then(t=>(0,d.isFolder)(e)?this.corruptServerItemsMap(r)?((0,u.default)("[Sync] WARNING: Discarding corrupt folder description from server for "+e),!1):this.markChildren(e,r,t.toBeSaved,t.missingChildren).then(()=>!0):this.rs.local.setNodes(this.flush(t.toBeSaved)).then(()=>!0)):this.updateCommonTimestamp(e,i).then(()=>!0)}))}handleResponse(e,t,r){const o=this.interpretStatus(r.statusCode);if(o.successful){if("get"===t)return this.handleGetResponse(e,o,r.body,r.contentType,r.revision);if("put"===t||"delete"===t)return this.completePush(e,t,o.conflict,r.revision).then((function(){return!0}));throw new Error("cannot handle response for unknown action "+t)}{let t;return t=o.unAuth?new l.default:o.networkProblems?new h.default("Network request failed."):new Error("HTTP response code "+o.statusCode+" received."),this.dealWithFailure(e).then(()=>{throw this.rs._emit("error",t),t})}}finishTask(e){if(void 0!==e.action)return e.promise.then(t=>this.handleResponse(e.path,e.action,t),t=>((0,u.default)("[Sync] wireclient rejects its promise!",e.path,e.action,t),this.handleResponse(e.path,e.action,{statusCode:"offline"}))).then(t=>{if(delete this._timeStarted[e.path],delete this._running[e.path],t&&this._tasks[e.path]){for(let t=0;t{!this.hasTasks()||this.stopped?((0,u.default)("[Sync] Sync is done! Reschedule?",Object.getOwnPropertyNames(this._tasks).length,this.stopped),this.done||(this.done=!0,this.rs._emit("sync-done"))):setTimeout(()=>{this.doTasks()},10)})},t=>{(0,u.default)("[Sync] Error",t),delete this._timeStarted[e.path],delete this._running[e.path],this.rs._emit("sync-req-done"),this.done||(this.done=!0,this.rs._emit("sync-done"))});delete this._running[e.path]}doTasks(){let e,t,r=0;e=this.rs.remote.connected?this.rs.remote.online?this.numThreads:1:0;const o=e-Object.getOwnPropertyNames(this._running).length;if(o<=0)return!0;for(t in this._tasks)if(!this._running[t]&&(this._timeStarted[t]=this.now(),this._running[t]=this.doTask(t),this._running[t].then(this.finishTask.bind(this)),r++,r>=o))return!0;return r>=o}collectTasks(e){return o(this,void 0,void 0,(function*(){return this.hasTasks()||this.stopped?Promise.resolve():this.collectDiffTasks().then(t=>t||!1===e?Promise.resolve():this.collectRefreshTasks(),(function(e){throw e}))}))}addTask(e,t){this._tasks[e]||(this._tasks[e]=[]),"function"==typeof t&&this._tasks[e].push(t)}sync(){return this.done=!1,this.doTasks()?Promise.resolve():this.collectTasks().then(()=>{try{this.doTasks()}catch(e){(0,u.default)("[Sync] doTasks error",e)}},(function(e){throw(0,u.default)("[Sync] Sync error",e),new Error("Local cache unavailable")}))}static _rs_init(e){f=function(){(0,u.default)("[Sync] syncCycleCb calling syncCycle");const t=new s.default;t.isBrowser()&&function(e,t){function r(e){const r=t.getCurrentSyncInterval();i.default.isBackground=!e;const o=t.getCurrentSyncInterval();t._emit("sync-interval-change",{oldValue:r,newValue:o})}e.on("background",()=>r(!1)),e.on("foreground",()=>r(!0))}(t,e),e.sync||(e.sync=new v(e),e.syncStopped&&((0,u.default)("[Sync] Instantiating sync stopped"),e.sync.stopped=!0,delete e.syncStopped)),(0,u.default)("[Sync] syncCycleCb calling syncCycle"),e.syncCycle()},p=function(){e.removeEventListener("connected",p),e.startSync()},e.on("ready",f),e.on("connected",p)}static _rs_cleanup(e){e.stopSync(),e.removeEventListener("ready",f),e.removeEventListener("connected",p),e.sync=void 0,delete e.sync}}(0,d.applyMixins)(v,[a.default]),e.exports=v},function(e,t,r){"use strict";(function(t){var o=this&&this.__awaiter||function(e,t,r,o){return new(r||(r=Promise))((function(n,i){function s(e){try{u(o.next(e))}catch(e){i(e)}}function a(e){try{u(o.throw(e))}catch(e){i(e)}}function u(e){var t;e.done?n(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(s,a)}u((o=o.apply(e,t||[])).next())}))},n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const i=n(r(2)),s=n(r(11)),a=n(r(1)),u=r(0);let c;class h extends s.default{constructor(e){super(),this.addEvents(["change","local-events-done"]),this.db=e||c,this.db?(this.getsRunning=0,this.putsRunning=0,this.changesQueued={},this.changesRunning={},this.commitSlownessWarning=null):(0,a.default)("[IndexedDB] Failed to open DB")}getNodes(e){return o(this,void 0,void 0,(function*(){const t=[],r={};for(let o=0,n=e.length;o0?this.getNodesFromDb(t).then((function(e){for(const t in r)e[t]=r[t];return e})):Promise.resolve(r)}))}setNodes(e){return o(this,void 0,void 0,(function*(){for(const t in e)this.changesQueued[t]=e[t]||!1;return this.maybeFlush(),Promise.resolve()}))}maybeFlush(){0===this.putsRunning?this.flushChangesQueued():this.commitSlownessWarning||(this.commitSlownessWarning=t.setInterval((function(){console.warn("WARNING: waited more than 10 seconds for previous commit to finish")}),1e4))}flushChangesQueued(){this.commitSlownessWarning&&(clearInterval(this.commitSlownessWarning),this.commitSlownessWarning=null),Object.keys(this.changesQueued).length>0&&(this.changesRunning=this.changesQueued,this.changesQueued={},this.setNodesInDb(this.changesRunning).then(this.flushChangesQueued.bind(this)))}getNodesFromDb(e){return new Promise((t,r)=>{const o=this.db.transaction(["nodes"],"readonly"),n=o.objectStore("nodes"),i={};this.getsRunning++,e.map(e=>{n.get(e).onsuccess=t=>{i[e]=t.target.result}}),o.oncomplete=()=>{t(i),this.getsRunning--},o.onerror=o.onabort=()=>{r("get transaction error/abort"),this.getsRunning--}})}setNodesInDb(e){return o(this,void 0,void 0,(function*(){return new Promise((t,r)=>{const o=this.db.transaction(["nodes"],"readwrite"),n=o.objectStore("nodes"),i=(new Date).getTime();this.putsRunning++,(0,a.default)("[IndexedDB] Starting put",e,this.putsRunning);for(const t in e){const r=e[t];if("object"==typeof r)try{n.put(r)}catch(e){throw(0,a.default)("[IndexedDB] Error while putting",r,e),e}else try{n.delete(t)}catch(e){throw(0,a.default)("[IndexedDB] Error while removing",n,r,e),e}}o.oncomplete=()=>{this.putsRunning--,(0,a.default)("[IndexedDB] Finished put",e,this.putsRunning,(new Date).getTime()-i+"ms"),t()},o.onerror=()=>{this.putsRunning--,r("transaction error")},o.onabort=()=>{r("transaction abort"),this.putsRunning--}})}))}reset(e){const t=this.db.name;this.db.close(),h.clean(this.db.name,()=>{h.open(t,(t,r)=>{t?(0,a.default)("[IndexedDB] Error while resetting local storage",t):this.db=r,"function"==typeof e&&e(self)})})}forAllNodes(e){return o(this,void 0,void 0,(function*(){return new Promise(t=>{this.db.transaction(["nodes"],"readonly").objectStore("nodes").openCursor().onsuccess=r=>{const o=r.target.result;o?(e(this.migrate(o.value)),o.continue()):t()}})}))}closeDB(){0===this.putsRunning?this.db.close():setTimeout(this.closeDB.bind(this),100)}static open(e,t){const r=setTimeout((function(){t("timeout trying to open db")}),1e4);try{const o=indexedDB.open(e,2);o.onerror=function(){(0,a.default)("[IndexedDB] Opening DB failed",o),clearTimeout(r),t(o.error)},o.onupgradeneeded=function(e){const t=o.result;(0,a.default)("[IndexedDB] Upgrade: from ",e.oldVersion," to ",e.newVersion),1!==e.oldVersion&&((0,a.default)("[IndexedDB] Creating object store: nodes"),t.createObjectStore("nodes",{keyPath:"path"})),(0,a.default)("[IndexedDB] Creating object store: changes"),t.createObjectStore("changes",{keyPath:"path"})},o.onsuccess=function(){clearTimeout(r);const n=o.result;if(!n.objectStoreNames.contains("nodes")||!n.objectStoreNames.contains("changes"))return(0,a.default)("[IndexedDB] Missing object store. Resetting the database."),void h.clean(e,(function(){h.open(e,t)}));t(null,o.result)}}catch(o){(0,a.default)("[IndexedDB] Failed to open database: "+o),(0,a.default)("[IndexedDB] Resetting database and trying again."),clearTimeout(r),h.clean(e,(function(){h.open(e,t)}))}}static clean(e,t){const r=indexedDB.deleteDatabase(e);r.onsuccess=function(){(0,a.default)("[IndexedDB] Done removing DB"),t()},r.onerror=r.onabort=function(t){console.error('Failed to remove database "'+e+'"',t)}}static _rs_init(e){return new Promise((t,r)=>{h.open("remotestorage",(function(o,n){o?r(o):(c=n,n.onerror=()=>{e._emit("error",o)},t())}))})}static _rs_supported(){return new Promise((e,t)=>{const r=(0,u.getGlobalContext)();let o=!1;if("undefined"!=typeof navigator&&navigator.userAgent.match(/Android (2|3|4\.[0-3])/)&&(navigator.userAgent.match(/Chrome|Firefox/)||(o=!0)),"indexedDB"in r&&!o)try{const r=indexedDB.open("rs-check");r.onerror=function(){t()},r.onsuccess=function(){r.result.close(),indexedDB.deleteDatabase("rs-check"),e()}}catch(e){t()}else t()})}static _rs_cleanup(e){return new Promise(t=>{e.local&&e.local.closeDB(),h.clean("remotestorage",t)})}diffHandler(){}}(0,u.applyMixins)(h,[i.default]),e.exports=h}).call(this,r(6))},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=o(r(11)),i=o(r(2)),s=o(r(1)),a=r(0),u="remotestorage:cache:nodes:";function c(e){return e.substr(0,u.length)===u||"remotestorage:cache:changes:"===e.substr(0,"remotestorage:cache:changes:".length)}class h extends n.default{constructor(){super(),this.addEvents(["change","local-events-done"])}diffHandler(...e){}getNodes(e){const t={};for(let r=0,o=e.length;r{(0,s.default)("[LocalStorage] Removing",e),delete localStorage[e]})}}(0,a.applyMixins)(h,[i.default]),e.exports=h},function(e,t,r){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};const n=o(r(2)),i=o(r(11)),s=r(0);class a extends i.default{constructor(){super(),this._storage={},this.addEvents(["change","local-events-done"])}getNodes(e){const t={};for(let r=0,o=e.length;r= 301) && (xhr.status <= 302)) { + var location = xhr.getResponseHeader('Location'); + if (isSecure(location)) { + return __makeRequest(location); // follow redirect + } else { + return errorHandler(generateErrorObject({ + message: 'no redirect URL found', + url: url, + status: xhr.status + })); + } + } else { + return errorHandler(generateErrorObject({ + message: 'error during request', + url: url, + status: xhr.status + })); + } + } + + function __makeRequest() { + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + __processState(); + } + }; + + xhr.onload = function () { + __processState(); + }; + + xhr.ontimeout = function () { + return errorHandler(generateErrorObject({ + message: 'request timed out', + url: url, + status: xhr.status + })); + }; + + xhr.open('GET', url, true); + xhr.timeout = self.config.request_timeout; + xhr.setRequestHeader('Accept', 'application/jrd+json, application/json'); + xhr.send(); + } + + return __makeRequest(); + }; + + WebFinger.prototype.__isValidJSON = function (str) { + try { + JSON.parse(str); + } catch (e) { + return false; + } + return true; + }; + + WebFinger.prototype.__isLocalhost = function (host) { + var local = /^localhost(\.localdomain)?(\:[0-9]+)?$/; + return local.test(host); + }; + + // processes JRD object as if it's a webfinger response object + // looks for known properties and adds them to profile datat struct. + WebFinger.prototype.__processJRD = function (URL, JRD, errorHandler, successHandler) { + var parsedJRD = JSON.parse(JRD); + if ((typeof parsedJRD !== 'object') || + (typeof parsedJRD.links !== 'object')) { + if (typeof parsedJRD.error !== 'undefined') { + return errorHandler(generateErrorObject({ message: parsedJRD.error, request: URL })); + } else { + return errorHandler(generateErrorObject({ message: 'unknown response from server', request: URL })); + } + } + + var links = parsedJRD.links; + if (!Array.isArray(links)) { + links = []; + } + var result = { // webfinger JRD - object, json, and our own indexing + object: parsedJRD, + json: JRD, + idx: {} + }; + + result.idx.properties = { + 'name': undefined + }; + result.idx.links = JSON.parse(JSON.stringify(LINK_PROPERTIES)); + + // process links + links.map(function (link, i) { + if (LINK_URI_MAPS.hasOwnProperty(link.rel)) { + if (result.idx.links[LINK_URI_MAPS[link.rel]]) { + var entry = {}; + Object.keys(link).map(function (item, n) { + entry[item] = link[item]; + }); + result.idx.links[LINK_URI_MAPS[link.rel]].push(entry); + } + } + }); + + // process properties + var props = JSON.parse(JRD).properties; + for (var key in props) { + if (props.hasOwnProperty(key)) { + if (key === 'http://packetizer.com/ns/name') { + result.idx.properties.name = props[key]; + } + } + } + return successHandler(result); + }; + + WebFinger.prototype.lookup = function (address, cb) { + if (typeof address !== 'string') { + throw new Error('first parameter must be a user address'); + } else if (typeof cb !== 'function') { + throw new Error('second parameter must be a callback'); + } + + var self = this; + var host = ''; + if (address.indexOf('://') > -1) { + // other uri format + host = address.replace(/ /g,'').split('/')[2]; + } else { + // useraddress + host = address.replace(/ /g,'').split('@')[1]; + } + var uri_index = 0; // track which URIS we've tried already + var protocol = 'https'; // we use https by default + + if (self.__isLocalhost(host)) { + protocol = 'http'; + } + + function __buildURL() { + var uri = ''; + if (! address.split('://')[1]) { + // the URI has not been defined, default to acct + uri = 'acct:'; + } + return protocol + '://' + host + '/.well-known/' + + URIS[uri_index] + '?resource=' + uri + address; + } + + // control flow for failures, what to do in various cases, etc. + function __fallbackChecks(err) { + if ((self.config.uri_fallback) && (host !== 'webfist.org') && (uri_index !== URIS.length - 1)) { // we have uris left to try + uri_index = uri_index + 1; + return __call(); + } else if ((!self.config.tls_only) && (protocol === 'https')) { // try normal http + uri_index = 0; + protocol = 'http'; + return __call(); + } else if ((self.config.webfist_fallback) && (host !== 'webfist.org')) { // webfist attempt + uri_index = 0; + protocol = 'http'; + host = 'webfist.org'; + // webfist will + // 1. make a query to the webfist server for the users account + // 2. from the response, get a link to the actual webfinger json data + // (stored somewhere in control of the user) + // 3. make a request to that url and get the json + // 4. process it like a normal webfinger response + var URL = __buildURL(); + self.__fetchJRD(URL, cb, function (data) { // get link to users JRD + self.__processJRD(URL, data, cb, function (result) { + if ((typeof result.idx.links.webfist === 'object') && + (typeof result.idx.links.webfist[0].href === 'string')) { + self.__fetchJRD(result.idx.links.webfist[0].href, cb, function (JRD) { + self.__processJRD(URL, JRD, cb, function (result) { + return cb(null, cb); + }); + }); + } + }); + }); + } else { + return cb(err); + } + } + + function __call() { + // make request + var URL = __buildURL(); + self.__fetchJRD(URL, __fallbackChecks, function (JRD) { + self.__processJRD(URL, JRD, cb, function (result) { cb(null, result); }); + }); + } + + return setTimeout(__call, 0); + }; + + WebFinger.prototype.lookupLink = function (address, rel, cb) { + if (LINK_PROPERTIES.hasOwnProperty(rel)) { + this.lookup(address, function (err, p) { + var links = p.idx.links[rel]; + if (err) { + return cb(err); + } else if (links.length === 0) { + return cb('no links found with rel="' + rel + '"'); + } else { + return cb(null, links[0]); + } + }); + } else { + return cb('unsupported rel ' + rel); + } + }; + + + + // AMD support + if (true) { + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function () { return WebFinger; }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + // CommonJS and Node.js module support. + } else {} +})(this); + + +/***/ }), + +/***/ "./node_modules/webpack/buildin/global.js": +/*!***********************************!*\ + !*** (webpack)/buildin/global.js ***! + \***********************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +var g; + +// This works in non-strict mode +g = (function() { + return this; +})(); + +try { + // This works if eval is allowed (see CSP) + g = g || new Function("return this")(); +} catch (e) { + // This works if the window reference is available + if (typeof window === "object") g = window; +} + +// g can still be undefined, but nothing to do about it... +// We return undefined, instead of nothing here, so it's +// easier to handle this case. if(!global) { ...} + +module.exports = g; + + +/***/ }), + +/***/ "./node_modules/xhr2/lib/browser.js": +/*!******************************************!*\ + !*** ./node_modules/xhr2/lib/browser.js ***! + \******************************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +module.exports = XMLHttpRequest; + + +/***/ }), + +/***/ "./src/access.ts": +/*!***********************!*\ + !*** ./src/access.ts ***! + \***********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/** + * @class Access + * + * Keeps track of claimed access and scopes. + */ +class Access { + constructor() { + this.reset(); + } + // TODO create custom type for init function + static _rs_init() { + return; + } + /** + * Property: scopes + * + * Holds an array of claimed scopes in the form + * > { name: "", mode: "" } + */ + get scopes() { + return Object.keys(this.scopeModeMap).map((key) => { + return { name: key, mode: this.scopeModeMap[key] }; + }); + } + get scopeParameter() { + return this.scopes.map((scope) => { + return `${this._scopeNameForParameter(scope)}:${scope.mode}`; + }).join(' '); + } + /** + * Claim access on a given scope with given mode. + * + * @param {string} scope - An access scope, such as "contacts" or "calendar" + * @param {string} mode - Access mode. Either "r" for read-only or "rw" for read/write + */ + claim(scope, mode) { + if (typeof (scope) !== 'string' || scope.indexOf('/') !== -1 || scope.length === 0) { + throw new Error('Scope should be a non-empty string without forward slashes'); + } + if (!mode.match(/^rw?$/)) { + throw new Error('Mode should be either \'r\' or \'rw\''); + } + this._adjustRootPaths(scope); + this.scopeModeMap[scope] = mode; + } + /** + * Get the access mode for a given scope. + * + * @param {string} scope - Access scope + * @returns {string} Access mode + */ + get(scope) { + return this.scopeModeMap[scope]; + } + /** + * Remove access for the given scope. + * + * @param {string} scope - Access scope + */ + remove(scope) { + const savedMap = {}; + for (const name in this.scopeModeMap) { + savedMap[name] = this.scopeModeMap[name]; + } + this.reset(); + delete savedMap[scope]; + for (const name in savedMap) { + this.claim(name, savedMap[name]); + } + } + /** + * Verify permission for a given scope. + * + * @param {string} scope - Access scope + * @param {string} mode - Access mode + * @returns {boolean} true if the requested access mode is active, false otherwise + */ + checkPermission(scope, mode) { + const actualMode = this.get(scope); + return actualMode && (mode === 'r' || actualMode === 'rw'); + } + /** + * Verify permission for a given path. + * + * @param {string} path - Path + * @param {string} mode - Access mode + * @returns {boolean} true if the requested access mode is active, false otherwise + */ + checkPathPermission(path, mode) { + if (this.checkPermission('*', mode)) { + return true; + } + // TODO check if this is reliable + const scope = this._getModuleName(path); + return !!this.checkPermission(scope, mode); + } + /** + * Reset all access permissions. + */ + reset() { + this.rootPaths = []; + this.scopeModeMap = {}; + } + /** + * Return the module name for a given path. + */ + _getModuleName(path) { + if (path[0] !== '/') { + throw new Error('Path should start with a slash'); + } + const moduleMatch = path.replace(/^\/public/, '').match(/^\/([^/]*)\//); + return moduleMatch ? moduleMatch[1] : '*'; + } + /** + * TODO: document + */ + _adjustRootPaths(newScope) { + if ('*' in this.scopeModeMap || newScope === '*') { + this.rootPaths = ['/']; + } + else if (!(newScope in this.scopeModeMap)) { + this.rootPaths.push('/' + newScope + '/'); + this.rootPaths.push('/public/' + newScope + '/'); + } + } + /** + * TODO: document + */ + _scopeNameForParameter(scope) { + if (scope.name === '*' && this.storageType) { + if (this.storageType === '2012.04') { + return ''; + } + else if (this.storageType.match(/remotestorage-0[01]/)) { + return 'root'; + } + } + return scope.name; + } + /** + * Set the storage type of the remote. + * + * @param {string} type - Storage type + */ + setStorageType(type) { + this.storageType = type; + } +} +module.exports = Access; + + +/***/ }), + +/***/ "./src/authorize.ts": +/*!**************************!*\ + !*** ./src/authorize.ts ***! + \**************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +const unauthorized_error_1 = __importDefault(__webpack_require__(/*! ./unauthorized-error */ "./src/unauthorized-error.ts")); +const requests_1 = __webpack_require__(/*! ./requests */ "./src/requests.ts"); +// This is set in _rs_init and needed for removal in _rs_cleanup +let onFeaturesLoaded; +function extractParams(url) { + // FF already decodes the URL fragment in document.location.hash, so use this instead: + // eslint-disable-next-line + const location = url || Authorize.getLocation().href; + const queryParam = {}; + for (const [key, value] of new URL(location).searchParams) { + queryParam[key] = value; + } + const hashPos = location.indexOf('#'); + if (hashPos === -1) { + return queryParam; + } + const urlFragment = location.substring(hashPos + 1); + // if hash is not of the form #key=val&key=val, it's probably not for us + if (!urlFragment.includes('=')) { + return queryParam; + } + return urlFragment.split('&').reduce(function (params, kvs) { + const kv = kvs.split('='); + if (kv[0] === 'state' && kv[1].match(/rsDiscovery/)) { + // extract rsDiscovery data from the state param + let stateValue = decodeURIComponent(kv[1]); + const encodedData = stateValue.substr(stateValue.indexOf('rsDiscovery=')) + .split('&')[0] + .split('=')[1]; + params['rsDiscovery'] = JSON.parse(atob(encodedData)); + // remove rsDiscovery param + stateValue = stateValue.replace(new RegExp('&?rsDiscovery=' + encodedData), ''); + if (stateValue.length > 0) { + params['state'] = stateValue; + } + } + else { + params[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]); + } + return params; + }, queryParam); +} +function buildOAuthURL(options) { + const redirect = new URL(options.redirectUri); + if (!options.state) { + options.state = redirect.hash ? redirect.hash.substring(1) : ''; + } + if (!options.response_type) { + options.response_type = 'token'; + } + const url = new URL(options.authURL); + // We don't add a trailing slash as only pathname to redirectUri. + url.searchParams.set('redirect_uri', options.redirectUri.replace(/#.*$/, '')); + url.searchParams.set('scope', options.scope); + url.searchParams.set('client_id', options.clientId); + for (const key of ['state', 'response_type', 'code_challenge', 'code_challenge_method', 'token_access_type']) { + const value = options[key]; + if (value) { + url.searchParams.set(key, value); + } + } + return url.href; +} +class Authorize { + /** + * Navigates browser to provider's OAuth page. When user grants access, + * browser will navigate back to redirectUri and OAuth will continue + * with onFeaturesLoaded. + */ + static authorize(remoteStorage, options) { + (0, log_1.default)('[Authorize] authURL = ', options.authURL, 'scope = ', options.scope, 'redirectUri = ', options.redirectUri, 'clientId = ', options.clientId, 'response_type =', options.response_type); + if (!options.scope) { + throw new Error("Cannot authorize due to undefined or empty scope; did you forget to access.claim()?"); + } + // TODO add a test for this + // keep track of the discovery data during redirect if we can't save it in localStorage + if (!(0, util_1.localStorageAvailable)() && remoteStorage.backend === 'remotestorage') { + options.redirectUri += options.redirectUri.indexOf('#') > 0 ? '&' : '#'; + const discoveryData = { + userAddress: remoteStorage.remote.userAddress, + href: remoteStorage.remote.href, + storageApi: remoteStorage.remote.storageApi, + properties: remoteStorage.remote.properties + }; + options.redirectUri += 'rsDiscovery=' + (0, util_1.toBase64)(JSON.stringify(discoveryData)); + } + const url = buildOAuthURL(options); + // FIXME declare potential `cordova` property on global somehow, so we don't have to + // use a string accessor here. + if (util_1.globalContext['cordova']) { + Authorize + .openWindow(url, options.redirectUri, 'location=yes,clearsessioncache=yes,clearcache=yes') + .then((authResult) => { + remoteStorage.remote.configure({ token: authResult.access_token }); + }); + return; + } + Authorize.setLocation(url); + } + /** On success, calls remote.configure() with new access token */ + static refreshAccessToken(rs, remote, refreshToken) { + var _a, _b, _c; + return __awaiter(this, void 0, void 0, function* () { + yield remote.configure({ token: null, tokenType: null }); + const formValues = new URLSearchParams({ + grant_type: 'refresh_token', + client_id: remote.clientId, + refresh_token: refreshToken, + }); + const xhr = yield (0, requests_1.requestWithTimeout)('POST', remote.TOKEN_URL, { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: formValues.toString(), + responseType: 'json' + }); + if ((xhr === null || xhr === void 0 ? void 0 : xhr.status) === 200) { + (0, log_1.default)(`[Authorize] access token good for ${(_a = xhr === null || xhr === void 0 ? void 0 : xhr.response) === null || _a === void 0 ? void 0 : _a.expires_in} seconds`); + const settings = { + token: (_b = xhr === null || xhr === void 0 ? void 0 : xhr.response) === null || _b === void 0 ? void 0 : _b.access_token, + tokenType: (_c = xhr === null || xhr === void 0 ? void 0 : xhr.response) === null || _c === void 0 ? void 0 : _c.token_type, + }; + if (settings.token) { + yield remote.configure(settings); + } + else { + throw new Error(`no access_token in "successful" refresh: ${xhr.response}`); + } + } + else { + yield remote.configure({ refreshToken: null }); + throw new unauthorized_error_1.default("refresh token rejected:" + JSON.stringify(xhr.response)); + } + }); + } + /** + * Set current document location + * + * Override this method if access to document.location is forbidden + */ + static setLocation(location) { + if (typeof location === 'string') { + document.location.href = location; + } + else if (typeof location === 'object') { + document.location = location; + } + else { + throw "Invalid location " + location; + } + } + static _rs_supported() { + return typeof (document) !== 'undefined'; + } + static _rs_cleanup(remoteStorage) { + remoteStorage.removeEventListener('features-loaded', onFeaturesLoaded); + } +} +Authorize.IMPLIED_FAKE_TOKEN = false; +/** + * Get current document location + * + * Override this method if access to document.location is forbidden + */ +Authorize.getLocation = function () { + return document.location; +}; +/** + * Open new InAppBrowser window for OAuth in Cordova + */ +Authorize.openWindow = function (url, redirectUri, options) { + return new Promise((resolve, reject) => { + const newWindow = open(url, '_blank', options); + if (!newWindow || newWindow.closed) { + reject('Authorization popup was blocked'); + return; + } + function handleExit() { + reject('Authorization was canceled'); + } + function handleLoadstart(event) { + if (event.url.indexOf(redirectUri) !== 0) { + return; + } + newWindow.removeEventListener('exit', handleExit); + newWindow.close(); + const authResult = extractParams(event.url); + if (!authResult) { + reject('Authorization error'); + return; + } + resolve(authResult); + } + newWindow.addEventListener('loadstart', handleLoadstart); + newWindow.addEventListener('exit', handleExit); + }); +}; +Authorize._rs_init = function (remoteStorage) { + const params = extractParams(); + let location; + if (params) { + location = Authorize.getLocation(); + location.hash = ''; + } + // eslint-disable-next-line + onFeaturesLoaded = function () { + let authParamsUsed = false; + if (!params) { + remoteStorage.remote.stopWaitingForToken(); + return; + } + if (params.error) { + if (params.error === 'access_denied') { + throw new unauthorized_error_1.default('Authorization failed: access denied', { code: 'access_denied' }); + } + else { + throw new unauthorized_error_1.default(`Authorization failed: ${params.error}`); + } + } + // rsDiscovery came with the redirect, because it couldn't be + // saved in localStorage + if (params.rsDiscovery) { + remoteStorage.remote.configure(params.rsDiscovery); + } + if (params.access_token) { + remoteStorage.remote.configure({ token: params.access_token }); + authParamsUsed = true; + } + if (params.remotestorage) { + remoteStorage.connect(params.remotestorage); + authParamsUsed = true; + } + if (params.state) { + location = Authorize.getLocation(); + Authorize.setLocation(location.href.split('#')[0] + '#' + params.state); + } + if (params.code) { // OAuth2 code or PKCE flow + fetchTokens(params.code); // remote.configure() called asynchronously + authParamsUsed = true; + } + if (!authParamsUsed) { + remoteStorage.remote.stopWaitingForToken(); + } + }; + // OAuth2 PKCE flow + function fetchTokens(code) { + var _a, _b, _c, _d; + return __awaiter(this, void 0, void 0, function* () { + const codeVerifier = sessionStorage.getItem('remotestorage:codeVerifier'); + if (!codeVerifier) { + (0, log_1.default)("[Authorize] Ignoring OAuth code parameter, because no PKCE code verifier found in sessionStorage"); + return; + } + location = Authorize.getLocation(); + let redirectUri = location.origin; + if (location.pathname !== '/') { + redirectUri += location.pathname; + } + const formValues = new URLSearchParams({ + code: code, + grant_type: 'authorization_code', + client_id: remoteStorage.remote.clientId, + redirect_uri: redirectUri, + code_verifier: codeVerifier + }); + const xhr = yield (0, requests_1.requestWithTimeout)('POST', remoteStorage.remote.TOKEN_URL, { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: formValues.toString(), + responseType: 'json' + }); + switch (xhr.status) { + case 200: + (0, log_1.default)(`[Authorize] access token good for ${(_a = xhr === null || xhr === void 0 ? void 0 : xhr.response) === null || _a === void 0 ? void 0 : _a.expires_in} seconds`); + const settings = { + token: (_b = xhr === null || xhr === void 0 ? void 0 : xhr.response) === null || _b === void 0 ? void 0 : _b.access_token, + refreshToken: (_c = xhr === null || xhr === void 0 ? void 0 : xhr.response) === null || _c === void 0 ? void 0 : _c.refresh_token, + tokenType: (_d = xhr === null || xhr === void 0 ? void 0 : xhr.response) === null || _d === void 0 ? void 0 : _d.token_type, + }; + if (settings.token) { + remoteStorage.remote.configure(settings); + } + else { + remoteStorage._emit('error', new Error(`no access_token in "successful" response: ${xhr.response}`)); + } + sessionStorage.removeItem('remotestorage:codeVerifier'); + break; + default: + remoteStorage._emit('error', new Error(`${xhr.statusText}: ${xhr.response}`)); + } + }); + } + remoteStorage.on('features-loaded', onFeaturesLoaded); +}; +module.exports = Authorize; + + +/***/ }), + +/***/ "./src/baseclient.ts": +/*!***************************!*\ + !*** ./src/baseclient.ts ***! + \***************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const tv4_1 = __importDefault(__webpack_require__(/*! tv4 */ "./node_modules/tv4/tv4.js")); +const types_1 = __importDefault(__webpack_require__(/*! ./types */ "./src/types.ts")); +const schema_not_found_error_1 = __importDefault(__webpack_require__(/*! ./schema-not-found-error */ "./src/schema-not-found-error.ts")); +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const config_1 = __importDefault(__webpack_require__(/*! ./config */ "./src/config.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +function getModuleNameFromBase(path) { + const parts = path.split('/'); + return path.length > 2 ? parts[1] : 'root'; +} +/** + * Provides a high-level interface to access data below a given root path. + */ +class BaseClient { + constructor(storage, base) { + /** + * TODO document + * + * @private + */ + this.schemas = { + configurable: true, + get() { + return BaseClient.Types.inScope(this.moduleName); + } + }; + if (base[base.length - 1] !== '/') { + throw "Not a folder: " + base; + } + if (base === '/') { + // allow absolute and relative paths for the root scope. + this.makePath = (path) => { + return (path[0] === '/' ? '' : '/') + path; + }; + } + this.storage = storage; + this.base = base; + this.moduleName = getModuleNameFromBase(this.base); + this.addEvents(['change']); + this.on = this.on.bind(this); + storage.onChange(this.base, this._fireChange.bind(this)); + } + /** + * Instantiate a new client, scoped to a subpath of the current client's + * path. + * + * @param path - The path to scope the new client to + * + * @returns A new client operating on a subpath of the current base path + */ + scope(path) { + return new BaseClient(this.storage, this.makePath(path)); + } + /** + * Get a list of child nodes below a given path. + * + * @param {string} path - The path to query. It MUST end with a forward slash. + * @param {number} maxAge - (optional) Either ``false`` or the maximum age of + * cached listing in milliseconds. See :ref:`max-age`. + * + * @returns {Promise} A promise for an object representing child nodes + */ + // TODO add real return type + getListing(path, maxAge) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof path !== 'string') { + path = ''; + } + else if (path.length > 0 && !(0, util_1.isFolder)(path)) { + return Promise.reject("Not a folder: " + path); + } + return this.storage.get(this.makePath(path), maxAge).then((r) => { + return r.statusCode === 404 ? {} : r.body; + }); + }); + } + /** + * Get all objects directly below a given path. + * + * @param {string} path - Path to the folder. Must end in a forward slash. + * @param {number} maxAge - (optional) Either ``false`` or the maximum age of + * cached objects in milliseconds. See :ref:`max-age`. + * + * @returns {Promise} A promise for an object + */ + // TODO add real return type + getAll(path, maxAge) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof path !== 'string') { + path = ''; + } + else if (path.length > 0 && !(0, util_1.isFolder)(path)) { + return Promise.reject("Not a folder: " + path); + } + return this.storage.get(this.makePath(path), maxAge).then((r) => { + if (r.statusCode === 404) { + return {}; + } + if (typeof r.body === 'object') { + const keys = Object.keys(r.body); + // treat this like 404. it probably means a folder listing that + // has changes that haven't been pushed out yet. + if (keys.length === 0) { + return {}; + } + const calls = keys.map((key) => { + return this.storage.get(this.makePath(path + key), maxAge) + .then((o) => { + if (typeof o.body === 'string') { + try { + o.body = JSON.parse(o.body); + } + catch (e) { /* empty */ } + } + if (typeof o.body === 'object') { + r.body[key] = o.body; + } + }); + }); + return Promise.all(calls).then(() => { return r.body; }); + } + }); + }); + } + /** + * Get the file at the given path. A file is raw data, as opposed to + * a JSON object (use :func:`getObject` for that). + * + * @param {string} path - Relative path from the module root (without leading + * slash). + * @param {number} maxAge - (optional) Either ``false`` or the maximum age of + * the cached file in milliseconds. See :ref:`max-age`. + * + * @returns {Promise} A promise for an object + */ + // TODO add real return type + getFile(path, maxAge) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof path !== 'string') { + return Promise.reject('Argument \'path\' of baseClient.getFile must be a string'); + } + return this.storage.get(this.makePath(path), maxAge).then((r) => { + return { + data: r.body, + contentType: r.contentType, + revision: r.revision // (this is new) + }; + }); + }); + } + /** + * Store raw data at a given path. + * + * @param {string} mimeType - MIME media type of the data being stored + * @param {string} path - Path relative to the module root + * @param {string|ArrayBuffer|ArrayBufferView} body - Raw data to store + * + * @returns {Promise} A promise for the created/updated revision (ETag) + */ + storeFile(mimeType, path, body) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof mimeType !== 'string') { + return Promise.reject('Argument \'mimeType\' of baseClient.storeFile must be a string'); + } + if (typeof path !== 'string') { + return Promise.reject('Argument \'path\' of baseClient.storeFile must be a string'); + } + if ((typeof body !== 'string') && (typeof body !== 'object')) { + return Promise.reject('Argument \'body\' of baseClient.storeFile must be a string, ArrayBuffer, or ArrayBufferView'); + } + if (!this.storage.access.checkPathPermission(this.makePath(path), 'rw')) { + console.warn('WARNING: Editing a document to which only read access (\'r\') was claimed'); + } + return this.storage.put(this.makePath(path), body, mimeType).then((r) => { + if (r.statusCode === 200 || r.statusCode === 201) { + return r.revision; + } + else { + return Promise.reject("Request (PUT " + this.makePath(path) + ") failed with status: " + r.statusCode); + } + }); + }); + } + /** + * Get a JSON object from the given path. + * + * @param {string} path - Relative path from the module root (without leading + * slash). + * @param {number} maxAge - (optional) Either ``false`` or the maximum age of + * cached object in milliseconds. See :ref:`max-age`. + * + * @returns {Promise} A promise, which resolves with the requested object (or ``null`` + * if non-existent) + */ + // TODO add real return type + getObject(path, maxAge) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof path !== 'string') { + return Promise.reject('Argument \'path\' of baseClient.getObject must be a string'); + } + return this.storage.get(this.makePath(path), maxAge).then((r) => { + if (typeof r.body === 'object') { // will be the case for documents stored with rs.js <= 0.10.0-beta2 + return r.body; + } + else if (typeof r.body === 'string') { + try { + return JSON.parse(r.body); + } + catch (e) { + throw new Error("Not valid JSON: " + this.makePath(path)); + } + } + else if (typeof r.body !== 'undefined' && r.statusCode === 200) { + return Promise.reject("Not an object: " + this.makePath(path)); + } + }); + }); + } + /** + * Store object at given path. Triggers synchronization. + * + * See ``declareType()`` and :doc:`data types ` + * for an explanation of types + * + * For any given `path`, must not be called more frequently than once per second. + * + * @param {string} typeAlias - Unique type of this object within this module. + * @param {string} path - Path relative to the module root. + * @param {object} object - A JavaScript object to be stored at the given + * path. Must be serializable as JSON. + * + * @returns {Promise} Resolves with revision on success. Rejects with + * a ValidationError, if validations fail. + */ + // TODO add real return type + storeObject(typeAlias, path, object) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof typeAlias !== 'string') { + return Promise.reject('Argument \'typeAlias\' of baseClient.storeObject must be a string'); + } + if (typeof path !== 'string') { + return Promise.reject('Argument \'path\' of baseClient.storeObject must be a string'); + } + if (typeof object !== 'object') { + return Promise.reject('Argument \'object\' of baseClient.storeObject must be an object'); + } + this._attachType(object, typeAlias); + try { + const validationResult = this.validate(object); + if (!validationResult.valid) { + return Promise.reject(validationResult); + } + } + catch (exc) { + return Promise.reject(exc); + } + return this.storage.put(this.makePath(path), JSON.stringify(object), 'application/json; charset=UTF-8').then((r) => { + if (r.statusCode === 200 || r.statusCode === 201) { + return r.revision; + } + else { + return Promise.reject("Request (PUT " + this.makePath(path) + ") failed with status: " + r.statusCode); + } + }); + }); + } + /** + * Remove node at given path from storage. Triggers synchronization. + * + * @param {string} path - Path relative to the module root. + * @returns {Promise} + */ + // TODO add real return type + remove(path) { + if (typeof path !== 'string') { + return Promise.reject('Argument \'path\' of baseClient.remove must be a string'); + } + if (!this.storage.access.checkPathPermission(this.makePath(path), 'rw')) { + console.warn('WARNING: Removing a document to which only read access (\'r\') was claimed'); + } + return this.storage.delete(this.makePath(path)); + } + /** + * Retrieve full URL of a document. Useful for example for sharing the public + * URL of an item in the ``/public`` folder. + * TODO: refactor this into the Remote interface + * + * @param {string} path - Path relative to the module root. + * @returns {string} The full URL of the item, including the storage origin + */ + getItemURL(path) { + if (typeof path !== 'string') { + throw 'Argument \'path\' of baseClient.getItemURL must be a string'; + } + if (this.storage.connected) { + path = (0, util_1.cleanPath)(this.makePath(path)); + return this.storage.remote.href + path; + } + else { + return undefined; + } + } + /** + * Set caching strategy for a given path and its children. + * + * See :ref:`caching-strategies` for a detailed description of the available + * strategies. + * + * @param {string} path - Path to cache + * @param {string} strategy - Caching strategy. One of 'ALL', 'SEEN', or + * 'FLUSH'. Defaults to 'ALL'. + * + * @returns {BaseClient} The same instance this is called on to allow for method chaining + */ + cache(path, strategy = 'ALL') { + if (typeof path !== 'string') { + throw 'Argument \'path\' of baseClient.cache must be a string'; + } + if (typeof strategy !== 'string') { + throw 'Argument \'strategy\' of baseClient.cache must be a string or undefined'; + } + if (strategy !== 'FLUSH' && + strategy !== 'SEEN' && + strategy !== 'ALL') { + throw 'Argument \'strategy\' of baseclient.cache must be one of ' + + '["FLUSH", "SEEN", "ALL"]'; + } + this.storage.caching.set(this.makePath(path), strategy); + return this; + } + /** + * TODO: document + * + * @param {string} path + */ + // TODO add return type once known + flush(path) { + return this.storage.local.flush(path); + } + /** + * Declare a remoteStorage object type using a JSON schema. + * + * See :doc:`Defining data types ` for more info. + * + * @param {string} alias - A type alias/shortname + * @param {uri} uri - (optional) JSON-LD URI of the schema. Automatically generated if none given + * @param {object} schema - A JSON Schema object describing the object type + **/ + declareType(alias, uriOrSchema, schema) { + let uri; + if (schema && typeof uriOrSchema === 'string') { + uri = uriOrSchema; + } + else if (!schema && typeof uriOrSchema !== 'string') { + schema = uriOrSchema; + uri = this._defaultTypeURI(alias); + } + else if (!schema && typeof uriOrSchema === 'string') { + throw new Error('declareType() requires a JSON Schema object to be passed, in order to validate object types/formats'); + } + BaseClient.Types.declare(this.moduleName, alias, uri, schema); + } + /** + * Validate an object against the associated schema. + * + * @param {Object} object - JS object to validate. Must have a ``@context`` property. + * + * @returns {Object} An object containing information about validation errors + **/ + validate(object) { + const schema = BaseClient.Types.getSchema(object['@context']); + if (schema) { + return tv4_1.default.validateResult(object, schema); + } + else { + throw new schema_not_found_error_1.default(object['@context']); + } + } + /** + * The default JSON-LD @context URL for RS types/objects/documents + * + * @private + */ + _defaultTypeURI(alias) { + return 'http://remotestorage.io/spec/modules/' + encodeURIComponent(this.moduleName) + '/' + encodeURIComponent(alias); + } + /** + * Attaches the JSON-LD @content to an object + * + * @private + */ + _attachType(object, alias) { + object['@context'] = BaseClient.Types.resolveAlias(this.moduleName + '/' + alias) || this._defaultTypeURI(alias); + } + /** + * TODO: document + * + * @private + */ + makePath(path) { + return this.base + (path || ''); + } + /** + * TODO: document + * + * @private + */ + _fireChange(event) { + if (config_1.default.changeEvents[event.origin]) { + ['new', 'old', 'lastCommon'].forEach(function (fieldNamePrefix) { + if ((!event[fieldNamePrefix + 'ContentType']) + || (/^application\/(.*)json(.*)/.exec(event[fieldNamePrefix + 'ContentType']))) { + if (typeof event[fieldNamePrefix + 'Value'] === 'string') { + try { + event[fieldNamePrefix + 'Value'] = JSON.parse(event[fieldNamePrefix + 'Value']); + } + catch (e) { + // empty + } + } + } + }); + this._emit('change', event); + } + } + static _rs_init() { + return; + } +} +BaseClient.Types = types_1.default; +(0, util_1.applyMixins)(BaseClient, [eventhandling_1.default]); +module.exports = BaseClient; + + +/***/ }), + +/***/ "./src/caching.ts": +/*!************************!*\ + !*** ./src/caching.ts ***! + \************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +/** + * @class Caching + * + * Holds/manages caching configuration. + **/ +class Caching { + constructor() { + this.pendingActivations = []; + this.reset(); + } + /** + * Configure caching for a given path explicitly. + * + * Not needed when using ``enable``/``disable``. + * + * @param {string} path - Path to cache + * @param {string} strategy - Caching strategy. One of 'ALL', 'SEEN', or 'FLUSH'. + */ + set(path, strategy) { + if (typeof path !== 'string') { + throw new Error('path should be a string'); + } + if (!(0, util_1.isFolder)(path)) { + throw new Error('path should be a folder'); + } + // FIXME We need to get to the access instance somehow. But I'm not sure + // this check is even necessary in the first place. -raucao + // if (!this._remoteStorage.access.checkPathPermission(path, 'r')) { + // throw new Error('No access to path "' + path + '". You have to claim access to it first.'); + // } + if (!strategy.match(/^(FLUSH|SEEN|ALL)$/)) { + throw new Error("strategy should be 'FLUSH', 'SEEN', or 'ALL'"); + } + this._rootPaths[path] = strategy; + if (strategy === 'ALL') { + if (this.activateHandler) { + this.activateHandler(path); + } + else { + this.pendingActivations.push(path); + } + } + } + /** + * Enable caching for a given path. + * + * Uses caching strategy ``ALL``. + * + * @param {string} path - Path to enable caching for + */ + enable(path) { + this.set(path, 'ALL'); + } + /** + * Disable caching for a given path. + * + * Uses caching strategy ``FLUSH`` (meaning items are only cached until + * successfully pushed to the remote). + * + * @param {string} path - Path to disable caching for + */ + disable(path) { + this.set(path, 'FLUSH'); + } + /** + * Set a callback for when caching is activated for a path. + * + * @param {function} cb - Callback function + */ + onActivate(cb) { + (0, log_1.default)('[Caching] Setting activate handler', cb, this.pendingActivations); + this.activateHandler = cb; + for (let i = 0; i < this.pendingActivations.length; i++) { + cb(this.pendingActivations[i]); + } + this.pendingActivations = []; + } + /** + * Retrieve caching setting for a given path, or its next parent + * with a caching strategy set. + * + * @param {string} path - Path to retrieve setting for + * @returns {string} caching strategy for the path + **/ + checkPath(path) { + if (this._rootPaths[path] !== undefined) { + return this._rootPaths[path]; + } + else if (path === '/') { + return 'SEEN'; + } + else { + return this.checkPath((0, util_1.containingFolder)(path)); + } + } + /** + * Reset the state of caching by deleting all caching information. + **/ + reset() { + this._rootPaths = {}; + } + /** + * Setup function that is called on initialization. + * + * @private + **/ + static _rs_init( /*remoteStorage*/) { + return; + } +} +module.exports = Caching; + + +/***/ }), + +/***/ "./src/cachinglayer.ts": +/*!*****************************!*\ + !*** ./src/cachinglayer.ts ***! + \*****************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const config_1 = __importDefault(__webpack_require__(/*! ./config */ "./src/config.ts")); +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +function getLatest(node) { + if (typeof (node) !== 'object' || typeof (node.path) !== 'string') { + return; + } + if ((0, util_1.isFolder)(node.path)) { + if (node.local && node.local.itemsMap) { + return node.local; + } + if (node.common && node.common.itemsMap) { + return node.common; + } + } + else { + if (node.local) { + if (node.local.body && node.local.contentType) { + return node.local; + } + if (node.local.body === false) { + return; + } + } + if (node.common && node.common.body && node.common.contentType) { + return node.common; + } + // Migration code! Once all apps use at least this version of the lib, we + // can publish clean-up code that migrates over any old-format data, and + // stop supporting it. For now, new apps will support data in both + // formats, thanks to this: + if (node.body && node.contentType) { + return { + body: node.body, + contentType: node.contentType + }; + } + } +} +function isOutdated(nodes, maxAge) { + for (const path in nodes) { + if (nodes[path] && nodes[path].remote) { + return true; + } + const nodeVersion = getLatest(nodes[path]); + if (nodeVersion && nodeVersion.timestamp && (new Date().getTime()) - nodeVersion.timestamp <= maxAge) { + return false; + } + else if (!nodeVersion) { + return true; + } + } + return true; +} +function makeNode(path) { + const node = { path: path, common: {} }; + if ((0, util_1.isFolder)(path)) { + node.common.itemsMap = {}; + } + return node; +} +function updateFolderNodeWithItemName(node, itemName) { + if (!node.common) { + node.common = { + itemsMap: {} + }; + } + if (!node.common.itemsMap) { + node.common.itemsMap = {}; + } + if (!node.local) { + node.local = (0, util_1.deepClone)(node.common); + } + if (!node.local.itemsMap) { + node.local.itemsMap = node.common.itemsMap; + } + node.local.itemsMap[itemName] = true; + return node; +} +/** + * This module defines functions that are mixed into remoteStorage.local when + * it is instantiated (currently one of indexeddb.js, localstorage.js, or + * inmemorystorage.js). + * + * All remoteStorage.local implementations should therefore implement + * this.getNodes, this.setNodes, and this.forAllNodes. The rest is blended in + * here to create a GPD (get/put/delete) interface which the BaseClient can + * talk to. + * + * @interface + */ +class CachingLayer { + constructor() { + // FIXME + // this process of updating nodes needs to be heavily documented first, then + // refactored. Right now it's almost impossible to refactor as there's no + // explanation of why things are implemented certain ways or what the goal(s) + // of the behavior are. -slvrbckt (+1 -les) + this._updateNodesRunning = false; + this._updateNodesQueued = []; + } + // -------------------------------------------------- + // TODO: improve our code structure so that this function + // could call sync.queueGetRequest directly instead of needing + // this hacky third parameter as a callback + get(path, maxAge, queueGetRequest) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof (maxAge) === 'number') { + return this.getNodes((0, util_1.pathsFromRoot)(path)) + .then((objs) => { + const node = getLatest(objs[path]); + if (isOutdated(objs, maxAge)) { + return queueGetRequest(path); + } + else if (node) { + return { + statusCode: 200, + body: node.body || node.itemsMap, + contentType: node.contentType + }; + } + else { + return { statusCode: 404 }; + } + }); + } + else { + return this.getNodes([path]) + .then((objs) => { + const node = getLatest(objs[path]); + if (node) { + if ((0, util_1.isFolder)(path)) { + for (const i in node.itemsMap) { + // the hasOwnProperty check here is only because our jshint settings require it: + if (node.itemsMap.hasOwnProperty(i) && node.itemsMap[i] === false) { + delete node.itemsMap[i]; + } + } + } + return { + statusCode: 200, + body: node.body || node.itemsMap, + contentType: node.contentType + }; + } + else { + return { statusCode: 404 }; + } + }); + } + }); + } + put(path, body, contentType) { + return __awaiter(this, void 0, void 0, function* () { + const paths = (0, util_1.pathsFromRoot)(path); + function _processNodes(nodePaths, nodes) { + try { + for (let i = 0, len = nodePaths.length; i < len; i++) { + const nodePath = nodePaths[i]; + let node = nodes[nodePath]; + let previous; + if (!node) { + nodes[nodePath] = node = makeNode(nodePath); + } + // Document + if (i === 0) { + previous = getLatest(node); + node.local = { + body: body, + contentType: contentType, + previousBody: (previous ? previous.body : undefined), + previousContentType: (previous ? previous.contentType : undefined), + }; + } + // Folder + else { + const itemName = nodePaths[i - 1].substring(nodePath.length); + node = updateFolderNodeWithItemName(node, itemName); + } + } + return nodes; + } + catch (e) { + (0, log_1.default)('[Cachinglayer] Error during PUT', nodes, e); + throw e; + } + } + return this._updateNodes(paths, _processNodes); + }); + } + delete(path) { + const paths = (0, util_1.pathsFromRoot)(path); + return this._updateNodes(paths, function (nodePaths, nodes) { + for (let i = 0, len = nodePaths.length; i < len; i++) { + const nodePath = nodePaths[i]; + const node = nodes[nodePath]; + let previous; + if (!node) { + console.error('Cannot delete non-existing node ' + nodePath); + continue; + } + if (i === 0) { + // Document + previous = getLatest(node); + node.local = { + body: false, + previousBody: (previous ? previous.body : undefined), + previousContentType: (previous ? previous.contentType : undefined), + }; + } + else { + // Folder + if (!node.local) { + node.local = (0, util_1.deepClone)(node.common); + } + const itemName = nodePaths[i - 1].substring(nodePath.length); + delete node.local.itemsMap[itemName]; + if (Object.getOwnPropertyNames(node.local.itemsMap).length > 0) { + // This folder still contains other items, don't remove any further ancestors + break; + } + } + } + return nodes; + }); + } + flush(path) { + return this._getAllDescendentPaths(path).then((paths) => { + return this.getNodes(paths); + }).then((nodes) => { + for (const nodePath in nodes) { + const node = nodes[nodePath]; + if (node && node.common && node.local) { + this._emitChange({ + path: node.path, + origin: 'local', + oldValue: (node.local.body === false ? undefined : node.local.body), + newValue: (node.common.body === false ? undefined : node.common.body) + }); + } + nodes[nodePath] = undefined; + } + return this.setNodes(nodes); + }); + } + _emitChange(obj) { + if (config_1.default.changeEvents[obj.origin]) { + this._emit('change', obj); + } + } + fireInitial() { + if (!config_1.default.changeEvents.local) { + return; + } + this.forAllNodes((node) => { + if ((0, util_1.isDocument)(node.path)) { + const latest = getLatest(node); + if (latest) { + this._emitChange({ + path: node.path, + origin: 'local', + oldValue: undefined, + oldContentType: undefined, + newValue: latest.body, + newContentType: latest.contentType + }); + } + } + }).then(() => { + this._emit('local-events-done'); + }); + } + // TODO add proper type + onDiff(diffHandler) { + this.diffHandler = diffHandler; + } + migrate(node) { + if (typeof (node) === 'object' && !node.common) { + node.common = {}; + if (typeof (node.path) === 'string') { + if (node.path.substr(-1) === '/' && typeof (node.body) === 'object') { + node.common.itemsMap = node.body; + } + } + else { + //save legacy content of document node as local version + if (!node.local) { + node.local = {}; + } + node.local.body = node.body; + node.local.contentType = node.contentType; + } + } + return node; + } + _updateNodes(paths, _processNodes) { + return new Promise((resolve, reject) => { + this._doUpdateNodes(paths, _processNodes, { + resolve: resolve, + reject: reject + }); + }); + } + _doUpdateNodes(paths, _processNodes, promise) { + if (this._updateNodesRunning) { + this._updateNodesQueued.push({ + paths: paths, + cb: _processNodes, + promise: promise + }); + return; + } + else { + this._updateNodesRunning = true; + } + this.getNodes(paths).then((nodes) => { + const existingNodes = (0, util_1.deepClone)(nodes); + const changeEvents = []; + nodes = _processNodes(paths, nodes); + for (const path in nodes) { + const node = nodes[path]; + if ((0, util_1.equal)(node, existingNodes[path])) { + delete nodes[path]; + } + else if ((0, util_1.isDocument)(path)) { + if (!(0, util_1.equal)(node.local.body, node.local.previousBody) || + node.local.contentType !== node.local.previousContentType) { + changeEvents.push({ + path: path, + origin: 'window', + oldValue: node.local.previousBody, + newValue: node.local.body === false ? undefined : node.local.body, + oldContentType: node.local.previousContentType, + newContentType: node.local.contentType + }); + } + delete node.local.previousBody; + delete node.local.previousContentType; + } + } + this.setNodes(nodes).then(() => { + this._emitChangeEvents(changeEvents); + promise.resolve({ statusCode: 200 }); + }); + }).then(() => { + return Promise.resolve(); + }, (err) => { + promise.reject(err); + }).then(() => { + this._updateNodesRunning = false; + const nextJob = this._updateNodesQueued.shift(); + if (nextJob) { + this._doUpdateNodes(nextJob.paths, nextJob.cb, nextJob.promise); + } + }); + } + _emitChangeEvents(events) { + for (let i = 0, len = events.length; i < len; i++) { + this._emitChange(events[i]); + if (this.diffHandler) { + this.diffHandler(events[i].path); + } + } + } + _getAllDescendentPaths(path) { + if ((0, util_1.isFolder)(path)) { + return this.getNodes([path]).then((nodes) => { + const allPaths = [path]; + const latest = getLatest(nodes[path]); + const itemNames = Object.keys(latest.itemsMap); + const calls = itemNames.map((itemName) => { + return this._getAllDescendentPaths(path + itemName).then((paths) => { + for (let i = 0, len = paths.length; i < len; i++) { + allPaths.push(paths[i]); + } + }); + }); + return Promise.all(calls).then(() => { + return allPaths; + }); + }); + } + else { + return Promise.resolve([path]); + } + } + // treated as private but made public for unit testing + _getInternals() { + return { + getLatest: getLatest, + makeNode: makeNode, + isOutdated: isOutdated + }; + } +} +(0, util_1.applyMixins)(CachingLayer, [eventhandling_1.default]); +module.exports = CachingLayer; + + +/***/ }), + +/***/ "./src/config.ts": +/*!***********************!*\ + !*** ./src/config.ts ***! + \***********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/** + * The default config, merged with the object passed to the constructor of the + * RemoteStorage object + */ +const config = { + cache: true, + changeEvents: { + local: true, + window: false, + remote: true, + conflict: true + }, + cordovaRedirectUri: undefined, + logging: false, + modules: [], + // the following are not public and will probably be moved away from the + // default config + backgroundSyncInterval: 60000, + disableFeatures: [], + discoveryTimeout: 10000, + isBackground: false, + requestTimeout: 30000, + syncInterval: 10000 +}; +module.exports = config; + + +/***/ }), + +/***/ "./src/discover.ts": +/*!*************************!*\ + !*** ./src/discover.ts ***! + \*************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const webfinger_js_1 = __importDefault(__webpack_require__(/*! webfinger.js */ "./node_modules/webfinger.js/src/webfinger.js")); +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +// feature detection flags +let haveXMLHttpRequest, hasLocalStorage; +// used to store settings in localStorage +const SETTINGS_KEY = 'remotestorage:discover'; +// cache loaded from localStorage +// TODO use class property +let cachedInfo = {}; +/** + * This function deals with the Webfinger lookup, discovering a connecting + * user's storage details. + * + * @param {string} userAddress - user@host or URL + * + * @returns {Promise} A promise for an object with the following properties. + * href - Storage base URL, + * storageApi - RS protocol version, + * authUrl - OAuth URL, + * properties - Webfinger link properties + **/ +const Discover = function Discover(userAddress) { + return new Promise((resolve, reject) => { + if (userAddress in cachedInfo) { + return resolve(cachedInfo[userAddress]); + } + const webFinger = new webfinger_js_1.default({ + tls_only: false, + uri_fallback: true, + request_timeout: 5000 + }); + return webFinger.lookup(userAddress, function (err, response) { + if (err) { + return reject(err); + } + else if ((typeof response.idx.links.remotestorage !== 'object') || + (typeof response.idx.links.remotestorage.length !== 'number') || + (response.idx.links.remotestorage.length <= 0)) { + (0, log_1.default)("[Discover] WebFinger record for " + userAddress + " does not have remotestorage defined in the links section ", JSON.stringify(response.json)); + return reject("WebFinger record for " + userAddress + " does not have remotestorage defined in the links section."); + } + const rs = response.idx.links.remotestorage[0]; + const authURL = rs.properties['http://tools.ietf.org/html/rfc6749#section-4.2'] || + rs.properties['auth-endpoint']; + const storageApi = rs.properties['http://remotestorage.io/spec/version'] || + rs.type; + // cache fetched data + cachedInfo[userAddress] = { + href: rs.href, + storageApi: storageApi, + authURL: authURL, + properties: rs.properties + }; + if (hasLocalStorage) { + localStorage[SETTINGS_KEY] = JSON.stringify({ cache: cachedInfo }); + } + return resolve(cachedInfo[userAddress]); + }); + }); +}; +Discover.DiscoveryError = function (message) { + this.name = 'DiscoveryError'; + this.message = message; + this.stack = (new Error()).stack; +}; +Discover.DiscoveryError.prototype = Object.create(Error.prototype); +Discover.DiscoveryError.prototype.constructor = Discover.DiscoveryError; +Discover._rs_init = function ( /*remoteStorage*/) { + hasLocalStorage = (0, util_1.localStorageAvailable)(); + if (hasLocalStorage) { + try { + const settings = JSON.parse(localStorage[SETTINGS_KEY]); + cachedInfo = settings.cache; + } + catch (e) { + /* empty */ + } + } +}; +Discover._rs_supported = function () { + haveXMLHttpRequest = Object.prototype.hasOwnProperty.call(util_1.globalContext, 'XMLHttpRequest'); + return haveXMLHttpRequest; +}; +Discover._rs_cleanup = function () { + if (hasLocalStorage) { + delete localStorage[SETTINGS_KEY]; + } +}; +module.exports = Discover; + + +/***/ }), + +/***/ "./src/dropbox.ts": +/*!************************!*\ + !*** ./src/dropbox.ts ***! + \************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const baseclient_1 = __importDefault(__webpack_require__(/*! ./baseclient */ "./src/baseclient.ts")); +const revisioncache_1 = __importDefault(__webpack_require__(/*! ./revisioncache */ "./src/revisioncache.ts")); +const sync_error_1 = __importDefault(__webpack_require__(/*! ./sync-error */ "./src/sync-error.ts")); +const unauthorized_error_1 = __importDefault(__webpack_require__(/*! ./unauthorized-error */ "./src/unauthorized-error.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +const requests_1 = __webpack_require__(/*! ./requests */ "./src/requests.ts"); +const remote_1 = __webpack_require__(/*! ./remote */ "./src/remote.ts"); +const authorize_1 = __importDefault(__webpack_require__(/*! ./authorize */ "./src/authorize.ts")); +/** + * WORK IN PROGRESS, NOT RECOMMENDED FOR PRODUCTION USE + * + * Dropbox backend for RemoteStorage.js + * This file exposes a get/put/delete interface which is compatible with + * . + * + * When remoteStorage.backend is set to 'dropbox', this backend will + * initialize and replace remoteStorage.remote with remoteStorage.dropbox. + * + * In order to ensure compatibility with the public folder, + * gets hijacked to return the Dropbox public share URL. + * + * To use this backend, you need to specify the Dropbox app key like so: + * + * @example + * remoteStorage.setApiKeys({ + * dropbox: 'your-app-key' + * }); + * + * An app key can be obtained by registering your app at https://www.dropbox.com/developers/apps + * + * Known issues: + * + * - Storing files larger than 150MB is not yet supported + * - Listing and deleting folders with more than 10'000 files will cause problems + * - Content-Type is not supported; TODO: use file_properties + * - Dropbox preserves cases but is not case-sensitive + * - getItemURL is asynchronous which means it returns useful values + * after the syncCycle + */ +let hasLocalStorage; +const AUTH_URL = 'https://www.dropbox.com/oauth2/authorize'; +const ACCOUNT_URL = 'https://api.dropboxapi.com/2/users/get_current_account'; +const TOKEN_URL = 'https://api.dropboxapi.com/oauth2/token'; +const OAUTH_SCOPE = 'account_info.read files.content.read files.content.write files.metadata.read files.metadata.write'; +const SETTINGS_KEY = 'remotestorage:dropbox'; +const FOLDER_URL = 'https://api.dropboxapi.com/2/files/list_folder'; +const CONTINUE_URL = 'https://api.dropboxapi.com/2/files/list_folder/continue'; +const DOWNLOAD_URL = 'https://content.dropboxapi.com/2/files/download'; +const UPLOAD_URL = 'https://content.dropboxapi.com/2/files/upload'; +const DELETE_URL = 'https://api.dropboxapi.com/2/files/delete'; +const METADATA_URL = 'https://api.dropboxapi.com/2/files/get_metadata'; +const CREATE_SHARED_URL = 'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings'; +const LIST_SHARED_URL = 'https://api.dropbox.com/2/sharing/list_shared_links'; +const PATH_PREFIX = '/remotestorage'; +const NUM_RETRIES = 3; +/** + * Maps a remoteStorage path to a path in Dropbox. + * + * @param {string} path - Path + * @returns {string} Actual path in Dropbox + * + * @private + */ +function getDropboxPath(path) { + return (PATH_PREFIX + '/' + path).replace(/\/+$/, '').replace(/\/+/g, '/'); +} +// This function is simple and has OK performance compared to more +// complicated ones: https://jsperf.com/json-escape-unicode/4 +const charsToEncode = /[\u007f-\uffff]/g; +function httpHeaderSafeJson(obj) { + return JSON.stringify(obj).replace(charsToEncode, function (c) { + return '\\u' + ('000' + c.charCodeAt(0).toString(16)).slice(-4); + }); +} +function compareApiError(response, expect) { + return new RegExp('^' + expect.join('\\/') + '(\\/|$)').test(response.error_summary); +} +function isBinaryData(data) { + return data instanceof ArrayBuffer || (0, requests_1.isArrayBufferView)(data); +} +/** + * @class + */ +class Dropbox extends remote_1.RemoteBase { + constructor(rs) { + super(rs); + this.online = true; // TODO implement offline detection on failed request + this.storageApi = 'draft-dejong-remotestorage-19'; + this._initialFetchDone = false; + this.addEvents(['connected', 'not-connected']); + this.clientId = rs.apiKeys.dropbox.appKey; + this.TOKEN_URL = TOKEN_URL; + this._revCache = new revisioncache_1.default('rev'); + this._fetchDeltaCursor = null; + this._fetchDeltaPromise = null; + this._itemRefs = {}; + hasLocalStorage = (0, util_1.localStorageAvailable)(); + if (hasLocalStorage) { + const settings = (0, util_1.getJSONFromLocalStorage)(SETTINGS_KEY); + if (settings) { + this.configure(settings); // can't await in constructor + } + this._itemRefs = (0, util_1.getJSONFromLocalStorage)(`${SETTINGS_KEY}:shares`) || {}; + } + if (this.connected) { + setTimeout(this._emit.bind(this), 0, 'connected'); + } + } + /** + * Set the backed to 'dropbox' and start the authentication flow in order + * to obtain an API token from Dropbox. + */ + connect() { + return __awaiter(this, void 0, void 0, function* () { + // TODO handling when token is already present + try { + this.rs.setBackend('dropbox'); + if (this.token) { + hookIt(this.rs); + } + else { // OAuth2 PKCE + const { codeVerifier, codeChallenge, state } = yield (0, util_1.generateCodeVerifier)(); + sessionStorage.setItem('remotestorage:codeVerifier', codeVerifier); + sessionStorage.setItem('remotestorage:state', state); + this.rs.authorize({ + authURL: AUTH_URL, + scope: OAUTH_SCOPE, + clientId: this.clientId, + response_type: 'code', + state: state, + code_challenge: codeChallenge, + code_challenge_method: 'S256', + token_access_type: 'offline' + }); + } + } + catch (err) { + this.rs._emit('error', err); + this.rs.setBackend(undefined); + throw err; + } + }); + } + /** + * Sets the connected flag + * Accepts its parameters according to the . + * @param {Object} settings + * @param {string} [settings.userAddress] - The user's email address + * @param {string} [settings.token] - Authorization token + * @param {string} [settings.refreshToken] - OAuth2 PKCE refresh token + * @param {string} [settings.tokenType] - usually 'bearer' - no support for 'mac' tokens yet + * + * @protected + **/ + configure(settings) { + return __awaiter(this, void 0, void 0, function* () { + // We only update this.userAddress if settings.userAddress is set to a string or to null: + if (typeof settings.userAddress !== 'undefined') { + this.userAddress = settings.userAddress; + } + // Same for this.token. If only one of these two is set, we leave the other one at its existing value: + if (typeof settings.token !== 'undefined') { + this.token = settings.token; + } + if (typeof settings.refreshToken !== 'undefined') { + this.refreshToken = settings.refreshToken; + } + if (typeof settings.tokenType !== 'undefined') { + this.tokenType = settings.tokenType; + } + const writeSettingsToCache = () => { + if (hasLocalStorage) { + localStorage.setItem(SETTINGS_KEY, JSON.stringify({ + userAddress: this.userAddress, + token: this.token, + refreshToken: this.refreshToken, + tokenType: this.tokenType, + })); + } + }; + const handleError = () => { + this.connected = false; + if (hasLocalStorage) { + localStorage.removeItem(SETTINGS_KEY); + } + this.rs.setBackend(undefined); + }; + if (this.refreshToken || this.token) { + this.connected = true; + if (this.userAddress) { + this._emit('connected'); + writeSettingsToCache(); + } + else { + try { + const info = yield this.info(); + this.userAddress = info.email; + this._emit('connected'); + writeSettingsToCache(); + } + catch (err) { + this.connected = false; + this.rs._emit('error', new Error('Could not fetch user info.')); + writeSettingsToCache.apply(this); + } + } + } + else { + handleError(); + } + }); + } + /** + * Get all items in a folder. + * + * @param path {string} - path of the folder to get, with leading slash + * @return {Object} + * statusCode - HTTP status code + * body - array of the items found + * contentType - 'application/json; charset=UTF-8' + * revision - revision of the folder + * + * @private + */ + _getFolder(path) { + const revCache = this._revCache; + const processResponse = (resp) => { + let body; + if (resp.status !== 200 && resp.status !== 409) { + return Promise.reject('Unexpected response status: ' + resp.status); + } + try { + body = JSON.parse(resp.responseText); + } + catch (e) { + return Promise.reject(e); + } + if (resp.status === 409) { + if (compareApiError(body, ['path', 'not_found'])) { + // if the folder is not found, handle it as an empty folder + return Promise.resolve({}); + } + return Promise.reject(new Error('API returned an error: ' + body.error_summary)); + } + const listing = body.entries.reduce((map, item) => { + try { + const isDir = item['.tag'] === 'folder'; + const itemName = item.path_display.split('/').slice(-1)[0] + (isDir ? '/' : ''); + if (isDir) { + map[itemName] = { ETag: revCache.get(path + itemName) }; + } + else { + const date = new Date(item.server_modified); + map[itemName] = { ETag: item.rev, 'Content-Length': item.size, 'Last-Modified': date.toUTCString() }; + this._revCache.set(path + itemName, item.rev); + } + } + catch (err) { + console.error(`[Dropbox] folder “${path}” has entry ${JSON.stringify(item)}:`, err); + } + return map; + }, {}); + if (body.has_more) { + return loadNext(body.cursor).then(function (nextListing) { + return Object.assign(listing, nextListing); + }); + } + return Promise.resolve(listing); + }; + const loadNext = (cursor) => { + const params = { + body: { cursor: cursor } + }; + return this._request('POST', CONTINUE_URL, params).then(processResponse); + }; + return this._request('POST', FOLDER_URL, { + body: { + path: getDropboxPath(path) + } + }).then(processResponse).then(function (listing) { + return Promise.resolve({ + statusCode: 200, + body: listing, + contentType: 'application/json; charset=UTF-8', + revision: revCache.get(path) + }); + }); + } + /** + * Checks for the path in ``_revCache`` and decides based on that if file + * has changed. Calls ``_getFolder`` is the path points to a folder. + * + * Calls ``Dropbox.share`` afterwards to fill ``_itemRefs``. + * + * Compatible with ``WireClient.get`` + * + * @param path {string} - path of the folder to get, with leading slash + * @param options {Object} + * + * @protected + */ + get(path, options = {}) { + if (!this.connected) { + return Promise.reject("not connected (path: " + path + ")"); + } + const savedRev = this._revCache.get(path); + if (savedRev === null) { + // file was deleted server side + return Promise.resolve({ statusCode: 404 }); + } + if (options && options.ifNoneMatch) { + // We must wait for local revision cache to be initialized before + // checking if local revision is outdated + if (!this._initialFetchDone) { + return this.fetchDelta().then(() => { + return this.get(path, options); + }); + } + if (savedRev && (savedRev === options.ifNoneMatch)) { + // nothing changed. + return Promise.resolve({ statusCode: 304 }); + } + } + // use _getFolder for folders + if (path.slice(-1) === '/') { + return this._getFolder(path); + } + const params = { + headers: { + 'Dropbox-API-Arg': httpHeaderSafeJson({ path: getDropboxPath(path) }), + }, + responseType: 'arraybuffer' + }; + if (options && options.ifNoneMatch) { + params.headers['If-None-Match'] = options.ifNoneMatch; + } + return this._request('GET', DOWNLOAD_URL, params).then(resp => { + const status = resp.status; + let meta, body, mime, rev; + if (status !== 200 && status !== 409) { + return Promise.resolve({ statusCode: status }); + } + meta = resp.getResponseHeader('Dropbox-API-Result'); + //first encode the response as text, and later check if + //text appears to actually be binary data + return (0, util_1.getTextFromArrayBuffer)(resp.response, 'UTF-8').then(responseText => { + body = responseText; + if (status === 409) { + meta = body; + } + try { + meta = JSON.parse(meta); + } + catch (e) { + return Promise.reject(e); + } + if (status === 409) { + if (compareApiError(meta, ['path', 'not_found'])) { + return { statusCode: 404 }; + } + return Promise.reject(new Error('API error while downloading file ("' + path + '"): ' + meta.error_summary)); + } + mime = resp.getResponseHeader('Content-Type'); + rev = meta.rev; + this._revCache.set(path, rev); + this._shareIfNeeded(path); // There doesn't appear to be a need to await this. + if ((0, util_1.shouldBeTreatedAsBinary)(responseText, mime)) { + // return unprocessed response + body = resp.response; + } + else { + // handling json (always try) + try { + body = JSON.parse(body); + mime = 'application/json; charset=UTF-8'; + } + catch (e) { + //Failed parsing Json, assume it is something else then + } + } + return { + statusCode: status, + body: body, + contentType: mime, + revision: rev + }; + }); + }); + } + /** + * Checks for the path in ``_revCache`` and decides based on that if file + * has changed. + * + * Compatible with ``WireClient`` + * + * Calls ``Dropbox.share`` afterwards to fill ``_itemRefs``. + * + * @param {string} path - path of the folder to put, with leading slash + * @param {XMLHttpRequestBodyInit} body - Blob | BufferSource | FormData | URLSearchParams | string + * @param {string} contentType - MIME type of body + * @param {Object} options + * @param {string} options.ifNoneMatch - When *, only create or update the file if it doesn't yet exist + * @param {string} options.ifMatch - Only saves if this matches current revision + * @returns {Promise} Resolves with an object containing the status code, + * content-type and revision + * @protected + */ + put(path, body, contentType, options = {}) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.connected) { + throw new Error("not connected (path: " + path + ")"); + } + // check if file has changed and return 412 + const savedRev = this._revCache.get(path); + if (options && options.ifMatch && + savedRev && (savedRev !== options.ifMatch)) { + return { statusCode: 412, revision: savedRev }; + } + if (options && (options.ifNoneMatch === '*') && + savedRev && (savedRev !== 'rev')) { + return { statusCode: 412, revision: savedRev }; + } + if ((!contentType.match(/charset=/)) && isBinaryData(body)) { + contentType += '; charset=binary'; + } + if (body.length > 150 * 1024 * 1024) { + //https://www.dropbox.com/developers/core/docs#chunked-upload + throw new Error("Cannot upload file larger than 150MB"); + } + const needsMetadata = options && (options.ifMatch || (options.ifNoneMatch === '*')); + const uploadParams = { + body: body, + contentType: contentType, + path: path + }; + if (needsMetadata) { + const metadata = yield this._getMetadata(path); + if (options && (options.ifNoneMatch === '*') && metadata) { + // if !!metadata === true, the file exists + return { + statusCode: 412, + revision: metadata.rev + }; + } + if (options && options.ifMatch && metadata && (metadata.rev !== options.ifMatch)) { + return { + statusCode: 412, + revision: metadata.rev + }; + } + } + const result = yield this._uploadSimple(uploadParams); + this._shareIfNeeded(path); // There doesn't appear to be a need to await this. + return result; + }); + } + /** + * Checks for the path in ``_revCache`` and decides based on that if file + * has changed. + * + * Compatible with ``WireClient.delete`` + * + * Calls ``Dropbox.share`` afterwards to fill ``_itemRefs``. + * + * @param {string} path - path of the folder to delete, with leading slash + * @param {Object} options + * + * @protected + */ + 'delete'(path, options = {}) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.connected) { + throw new Error("not connected (path: " + path + ")"); + } + // check if file has changed and return 412 + const savedRev = this._revCache.get(path); + if ((options === null || options === void 0 ? void 0 : options.ifMatch) && savedRev && (options.ifMatch !== savedRev)) { + return { statusCode: 412, revision: savedRev }; + } + if (options === null || options === void 0 ? void 0 : options.ifMatch) { + const metadata = yield this._getMetadata(path); + if ((options === null || options === void 0 ? void 0 : options.ifMatch) && metadata && (metadata.rev !== options.ifMatch)) { + return { + statusCode: 412, + revision: metadata.rev + }; + } + } + return this._deleteSimple(path); + }); + } + /** + * Calls share, if the provided path resides in a public folder. + * @private + */ + _shareIfNeeded(path) { + if (path.match(/^\/public\/.*[^/]$/) && this._itemRefs[path] === undefined) { + return this.share(path); + } + } + /** + * Gets a publicly-accessible URL for the path from Dropbox and stores it + * in ``_itemRefs``. + * + * @return {Promise} a promise for the URL + * + * @private + */ + share(path) { + const options = { + body: { path: getDropboxPath(path) } + }; + return this._request('POST', CREATE_SHARED_URL, options).then((response) => { + if (response.status !== 200 && response.status !== 409) { + return Promise.reject(new Error('Invalid response status:' + response.status)); + } + let body; + try { + body = JSON.parse(response.responseText); + } + catch (e) { + return Promise.reject(new Error('Invalid response body: ' + response.responseText)); + } + if (response.status === 409) { + if (compareApiError(body, ['shared_link_already_exists'])) { + return this._getSharedLink(path); + } + return Promise.reject(new Error('API error: ' + body.error_summary)); + } + return Promise.resolve(body.url); + }).then((link) => { + this._itemRefs[path] = link; + if (hasLocalStorage) { + localStorage.setItem(SETTINGS_KEY + ':shares', JSON.stringify(this._itemRefs)); + } + return Promise.resolve(link); + }, (error) => { + error.message = 'Sharing Dropbox file or folder ("' + path + '") failed: ' + error.message; + return Promise.reject(error); + }); + } + /** + * Fetches the user's info from dropbox and returns a promise for it. + * + * @return {Promise} a promise for user info object (email - the user's email address) + * + * @protected + */ + info() { + return this._request('POST', ACCOUNT_URL, {}).then(function (response) { + let email; + try { + const info = JSON.parse(response.responseText); + email = info === null || info === void 0 ? void 0 : info.email; + } + catch (e) { + return Promise.reject(new Error('Could not query current account info: Invalid API response: ' + response.responseText)); + } + return Promise.resolve({ + email: email + }); + }); + } + /** + * Makes a network request. + * + * @param {string} method - Request method + * @param {string} url - Target URL + * @param {object} options - Request options + * @param {number} numAttempts - # of times same request repeated + * @returns {Promise} Resolves with the response of the network request + * + * @private + */ + _request(method, url, options, numAttempts = 1) { + return __awaiter(this, void 0, void 0, function* () { + if (this.isForbiddenRequestMethod(method, url)) { + throw `Don't use ${method} on directories!`; + } + if (!this.token) { + throw new unauthorized_error_1.default("No access token"); + } + if (!options.headers) { + options.headers = {}; + } + options.headers['Authorization'] = 'Bearer ' + this.token; + if (typeof options.body === 'object' && !isBinaryData(options.body)) { + options.body = JSON.stringify(options.body); + options.headers['Content-Type'] = 'application/json; charset=UTF-8'; + } + this.rs._emit('wire-busy', { + method: method, + isFolder: (0, util_1.isFolder)(url) + }); + try { + const xhr = yield (0, requests_1.requestWithTimeout)(method, url, options); + if (!this.online) { + this.online = true; + this.rs._emit('network-online'); + } + this.rs._emit('wire-done', { + method: method, + isFolder: (0, util_1.isFolder)(url), + success: true + }); + if ((xhr === null || xhr === void 0 ? void 0 : xhr.status) === 401 && this.refreshToken) { + if (numAttempts >= NUM_RETRIES) { + console.error(`Abandoned after ${numAttempts} attempts: ${method} ${url}`); + return xhr; + } + else { + this.rs._emit('wire-busy', { + method: method, + isFolder: (0, util_1.isFolder)(url) + }); + yield authorize_1.default.refreshAccessToken(this.rs, this, this.refreshToken); + this.rs._emit('wire-done', { + method: method, + isFolder: (0, util_1.isFolder)(url), + success: true + }); + // re-runs original request + return this._request(method, url, options, numAttempts + 1); + } + } + else if ([503, 429].includes(xhr === null || xhr === void 0 ? void 0 : xhr.status)) { + // 503 Service Unavailable; 429 Too Many Requests + if (this.online) { + this.online = false; + this.rs._emit('network-offline'); + } + if (numAttempts >= NUM_RETRIES) { + console.warn(`Abandoned after ${numAttempts} attempts: ${method} ${url}`); + return xhr; + } + else { + yield new Promise(resolve => setTimeout(resolve, (0, requests_1.retryAfterMs)(xhr))); + // re-runs original request + return this._request(method, url, options, numAttempts + 1); + } + } + else { + return xhr; + } + } + catch (error) { + if (this.online) { + this.online = false; + this.rs._emit('network-offline'); + } + this.rs._emit('wire-done', { + method: method, + isFolder: (0, util_1.isFolder)(url), + success: false + }); + throw error; + } + }); + } + /** + * Fetches the revision of all the files from dropbox API and puts them + * into ``_revCache``. These values can then be used to determine if + * something has changed. + * + * @private + */ + fetchDelta(...args) { + // If fetchDelta was already called, and didn't finish, return the existing + // promise instead of calling Dropbox API again + if (this._fetchDeltaPromise) { + return this._fetchDeltaPromise; + } + /** This should resolve (with no value) on success, and reject on error. */ + const fetch = (cursor) => __awaiter(this, void 0, void 0, function* () { + let url; + let requestBody; + if (typeof cursor === 'string') { + url = CONTINUE_URL; + requestBody = { cursor }; + } + else { + url = FOLDER_URL; + requestBody = { + path: PATH_PREFIX, + recursive: true, + include_deleted: true + }; + } + try { + const response = yield this._request('POST', url, { body: requestBody }); + if (response.status === 401) { + throw new unauthorized_error_1.default(); + } + if (response.status !== 200 && response.status !== 409) { + throw new Error('Invalid response status: ' + response.status); + } + let responseBody; + try { + responseBody = JSON.parse(response.responseText); + } + catch (e) { + throw new Error('Invalid response body: ' + response.responseText); + } + if (response.status === 409) { + if (compareApiError(responseBody, ['path', 'not_found'])) { + responseBody = { + cursor: null, + entries: [], + has_more: false + }; + } + else { + throw new Error('API returned an error: ' + responseBody.error_summary); + } + } + if (!cursor) { + //we are doing a complete fetch, so propagation would introduce unnecessary overhead + this._revCache.deactivatePropagation(); + } + responseBody.entries.forEach(entry => { + const path = entry.path_display.slice(PATH_PREFIX.length); + if (entry['.tag'] === 'deleted') { + // there's no way to know whether the entry was a file or a folder + this._revCache.delete(path); + this._revCache.delete(path + '/'); + } + else if (entry['.tag'] === 'file') { + this._revCache.set(path, entry.rev); + } + }); + this._fetchDeltaCursor = responseBody.cursor; + if (responseBody.has_more) { + return fetch(responseBody.cursor); + } + else { + this._revCache.activatePropagation(); + this._initialFetchDone = true; + } + } + catch (error) { + if (error === 'timeout') { + // Offline is handled elsewhere already, just ignore it here + return; + } + else { + throw error; + } + } + }); + this._fetchDeltaPromise = fetch(this._fetchDeltaCursor).catch(error => { + if (typeof (error) === 'object' && 'message' in error) { + error.message = 'Dropbox: fetchDelta: ' + error.message; + } + else { + error = `Dropbox: fetchDelta: ${error}`; + } + this.rs._emit('error', error); + this._fetchDeltaPromise = null; + return Promise.reject(error); + }).then(() => { + this._fetchDeltaPromise = null; + return Promise.resolve(args); + }); + return this._fetchDeltaPromise; + } + /** + * Gets metadata for a path (can point to either a file or a folder). + * + * @param {string} path - the path to get metadata for + * + * @returns {Promise} A promise for the metadata + * + * @private + */ + _getMetadata(path) { + const requestBody = { + path: getDropboxPath(path) + }; + return this._request('POST', METADATA_URL, { body: requestBody }).then((response) => { + if (response.status !== 200 && response.status !== 409) { + return Promise.reject(new Error('Invalid response status:' + response.status)); + } + let responseBody; + try { + responseBody = JSON.parse(response.responseText); + } + catch (e) { + return Promise.reject(new Error('Invalid response body: ' + response.responseText)); + } + if (response.status === 409) { + if (compareApiError(responseBody, ['path', 'not_found'])) { + return Promise.resolve(); + } + return Promise.reject(new Error('API error: ' + responseBody.error_summary)); + } + return Promise.resolve(responseBody); + }).then(undefined, (error) => { + error.message = 'Could not load metadata for file or folder ("' + path + '"): ' + error.message; + return Promise.reject(error); + }); + } + /** + * Upload a simple file (the size is no more than 150MB). + * + * @param {Object} params + * @param {string} params.ifMatch - Only update the file if its ETag + * matches this string + * @param {string} params.path - path of the file + * @param {string} params.body - contents of the file to upload + * @param {string} params.contentType - mime type of the file * + * @return {Promise} A promise for an object with the following structure: + * statusCode - HTTP status code + * revision - revision of the newly-created file, if any + * + * @private + */ + _uploadSimple(params) { + const args = { + path: getDropboxPath(params.path), + mode: { '.tag': 'overwrite', update: undefined }, + mute: true + }; + if (params.ifMatch) { + args.mode = { '.tag': 'update', update: params.ifMatch }; + } + return this._request('POST', UPLOAD_URL, { + body: params.body, + headers: { + 'Content-Type': 'application/octet-stream', + 'Dropbox-API-Arg': httpHeaderSafeJson(args) + } + }).then(response => { + if (response.status !== 200 && response.status !== 409) { + return Promise.resolve({ statusCode: response.status }); + } + let body; + try { + body = JSON.parse(response.responseText); + } + catch (e) { + return Promise.reject(new Error('Invalid API result: ' + response.responseText)); + } + if (response.status === 409) { + if (compareApiError(body, ['path', 'conflict'])) { + return this._getMetadata(params.path).then(function (metadata) { + return Promise.resolve({ + statusCode: 412, + revision: metadata.rev + }); + }); + } + this.rs._emit('error', new Error(body.error_summary)); + return Promise.resolve({ statusCode: response.status }); + } + this._revCache.set(params.path, body.rev); + return Promise.resolve({ statusCode: response.status, revision: body.rev }); + }); + } + /** + * Deletes a file or a folder. + * + * @param {string} path - the path to delete + * + * @returns {Promise} A promise for an object with the following structure: + * statusCode - HTTP status code + * + * @private + */ + _deleteSimple(path) { + const requestBody = { path: getDropboxPath(path) }; + return this._request('POST', DELETE_URL, { body: requestBody }).then((response) => { + if (response.status !== 200 && response.status !== 409) { + return Promise.resolve({ statusCode: response.status }); + } + let responseBody; + try { + responseBody = JSON.parse(response.responseText); + } + catch (e) { + return Promise.reject(new Error('Invalid response body: ' + response.responseText)); + } + if (response.status === 409) { + if (compareApiError(responseBody, ['path_lookup', 'not_found'])) { + return Promise.resolve({ statusCode: 404 }); + } + this.rs._emit('error', new Error(responseBody.error_summary)); + } + return Promise.resolve({ statusCode: response.status }); + }).then(result => { + if (result.statusCode === 200 || result.statusCode === 404) { + this._revCache.delete(path); + delete this._itemRefs[path]; + } + return Promise.resolve(result); + }, (error) => { + error.message = 'Could not delete Dropbox file or folder ("' + path + '"): ' + error.message; + return Promise.reject(error); + }); + } + /** + * Requests the link for an already-shared file or folder. + * + * @param {string} path - path to the file or folder + * + * @returns {Promise} A promise for the shared link + * + * @private + */ + _getSharedLink(path) { + return __awaiter(this, void 0, void 0, function* () { + const options = { + body: { + path: getDropboxPath(path), + direct_only: true + } + }; + return this._request('POST', LIST_SHARED_URL, options).then((response) => { + if (response.status !== 200 && response.status !== 409) { + return Promise.reject(new Error('Invalid response status: ' + response.status)); + } + let body; + try { + body = JSON.parse(response.responseText); + } + catch (e) { + return Promise.reject(new Error('Invalid response body: ' + response.responseText)); + } + if (response.status === 409) { + return Promise.reject(new Error('API error: ' + (body === null || body === void 0 ? void 0 : body.error_summary) || false)); + } + if (!body.links.length) { + return Promise.reject(new Error('No links returned')); + } + return Promise.resolve(body.links[0].url); + }, error => { + error.message = 'Could not get link to a shared file or folder ("' + path + '"): ' + error.message; + return Promise.reject(error); + }); + }); + } + /** + * Initialize the Dropbox backend. + * + * @param {object} rs - RemoteStorage instance + * + * @protected + */ + static _rs_init(rs) { + hasLocalStorage = (0, util_1.localStorageAvailable)(); + if (rs.apiKeys.dropbox) { + rs.dropbox = new Dropbox(rs); + } + if (rs.backend === 'dropbox') { + hookIt(rs); + } + } + /** + * Inform about the availability of the Dropbox backend. + * + * @returns {Boolean} + * + * @protected + */ + static _rs_supported() { + return true; + } + /** + * Remove Dropbox as a backend. + * + * @param {object} rs - RemoteStorage instance + * + * @protected + */ + static _rs_cleanup(rs) { + unHookIt(rs); + if (hasLocalStorage) { + localStorage.removeItem(SETTINGS_KEY); + } + rs.setBackend(undefined); + } +} +/** + * Hooking the sync + * + * TODO: document + */ +function hookSync(rs, ...args) { + if (rs._dropboxOrigSync) { + return; + } // already hooked + rs._dropboxOrigSync = rs.sync.sync.bind(rs.sync); + rs.sync.sync = function () { + return this.dropbox.fetchDelta(rs, ...args). + then(rs._dropboxOrigSync, function (err) { + rs._emit('error', new sync_error_1.default(err)); + rs._emit('sync-done'); + }); + }.bind(rs); +} +/** + * Unhooking the sync + * + * TODO: document + */ +function unHookSync(rs) { + if (!rs._dropboxOrigSync) { + return; + } // not hooked + rs.sync.sync = rs._dropboxOrigSync; + delete rs._dropboxOrigSync; +} +/** + * Hook RemoteStorage.syncCycle as it's the first function called + * after RemoteStorage.sync is initialized, so we can then hook + * the sync function + * @param {object} rs RemoteStorage instance + * @param {array} args remaining arguments + */ +function hookSyncCycle(rs, ...args) { + if (rs._dropboxOrigSyncCycle) { + return; + } // already hooked + rs._dropboxOrigSyncCycle = rs.syncCycle; + rs.syncCycle = () => { + if (rs.sync) { + hookSync(rs); + rs._dropboxOrigSyncCycle(rs, ...args); + unHookSyncCycle(rs); + } + else { + throw new Error('expected sync to be initialized by now'); + } + }; +} +/** + * Restore RemoteStorage's syncCycle original implementation + * @param {object} rs RemoteStorage instance + */ +function unHookSyncCycle(rs) { + if (!rs._dropboxOrigSyncCycle) { + return; + } // not hooked + rs.syncCycle = rs._dropboxOrigSyncCycle; + delete rs._dropboxOrigSyncCycle; +} +/** + * Overwrite BaseClient's getItemURL with our own implementation + * + * TODO: getItemURL still needs to be implemented + * + * @param {object} rs - RemoteStorage instance + * + * @private + */ +function hookGetItemURL(rs) { + if (rs._origBaseClientGetItemURL) { + return; + } + rs._origBaseClientGetItemURL = baseclient_1.default.prototype.getItemURL; + baseclient_1.default.prototype.getItemURL = function ( /*path*/) { + throw new Error('getItemURL is not implemented for Dropbox yet'); + }; +} +/** + * Restore BaseClient's getItemURL original implementation + * + * @param {object} rs - RemoteStorage instance + * + * @private + */ +function unHookGetItemURL(rs) { + if (!rs._origBaseClientGetItemURL) { + return; + } + baseclient_1.default.prototype.getItemURL = rs._origBaseClientGetItemURL; + delete rs._origBaseClientGetItemURL; +} +/** + * TODO: document + */ +function hookRemote(rs) { + if (rs._origRemote) { + return; + } + rs._origRemote = rs.remote; + rs.remote = rs.dropbox; +} +/** + * TODO: document + */ +function unHookRemote(rs) { + if (rs._origRemote) { + rs.remote = rs._origRemote; + delete rs._origRemote; + } +} +/** + * TODO: document + */ +function hookIt(rs) { + hookRemote(rs); + if (rs.sync) { + hookSync(rs); + } + else { + // when sync is not available yet, we hook the syncCycle function which is called + // right after sync is initialized + hookSyncCycle(rs); + } + hookGetItemURL(rs); +} +/** + * TODO: document + */ +function unHookIt(rs) { + unHookRemote(rs); + unHookSync(rs); + unHookGetItemURL(rs); + unHookSyncCycle(rs); +} +(0, util_1.applyMixins)(Dropbox, [eventhandling_1.default]); +module.exports = Dropbox; + + +/***/ }), + +/***/ "./src/env.ts": +/*!********************!*\ + !*** ./src/env.ts ***! + \********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +class Env { + constructor() { + this.addEvents(["background", "foreground"]); + this.mode = typeof (window) !== 'undefined' ? 'browser' : 'node'; + if (this.mode === 'browser') { + this.setBrowserPrefixedNames(); + document.addEventListener(this.visibilityChangeEvent, this.setVisibility.bind(this), false); + this.setVisibility(); + } + } + setBrowserPrefixedNames() { + if (this.mode !== 'browser') { + return; + } + if (typeof document.hidden !== "undefined") { + this.hiddenProperty = "hidden"; + this.visibilityChangeEvent = "visibilitychange"; + } + else if (typeof document["mozHidden"] !== "undefined") { + this.hiddenProperty = "mozHidden"; + this.visibilityChangeEvent = "mozvisibilitychange"; + } + else if (typeof document["msHidden"] !== "undefined") { + this.hiddenProperty = "msHidden"; + this.visibilityChangeEvent = "msvisibilitychange"; + } + else if (typeof document["webkitHidden"] !== "undefined") { + this.hiddenProperty = "webkitHidden"; + this.visibilityChangeEvent = "webkitvisibilitychange"; + } + } + setVisibility() { + if (document[this.hiddenProperty]) { + this.goBackground(); + } + else { + this.goForeground(); + } + } + isBrowser() { + return this.mode === "browser"; + } + isNode() { + return this.mode === "node"; + } + goBackground() { + this._emit("background"); + } + goForeground() { + this._emit("foreground"); + } + static _rs_init( /* remoteStorage */) { + return; + } + static _rs_cleanup( /* remoteStorage */) { + return; + } +} +(0, util_1.applyMixins)(Env, [eventhandling_1.default]); +module.exports = Env; + + +/***/ }), + +/***/ "./src/eventhandling.ts": +/*!******************************!*\ + !*** ./src/eventhandling.ts ***! + \******************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +class EventHandling { + /** + * Register event names + * + * TODO see if necessary, or can be done on the fly in addEventListener + */ + addEvents(additionalEvents) { + additionalEvents.forEach(evName => this._addEvent(evName)); + } + /** + * Install an event handler for the given event name + */ + addEventListener(eventName, handler) { + // Check type for public consumption of API + if (typeof (eventName) !== 'string') { + throw new Error('Argument eventName should be a string'); + } + if (typeof (handler) !== 'function') { + throw new Error('Argument handler should be a function'); + } + (0, log_1.default)('[EventHandling] Adding event listener', eventName); + this._validateEvent(eventName); + this._handlers[eventName].push(handler); + } + /* + * Alias for addEventListener + */ + on(eventName, handler) { + return this.addEventListener(eventName, handler); + } + /** + * Remove a previously installed event handler + */ + removeEventListener(eventName, handler) { + this._validateEvent(eventName); + const hl = this._handlers[eventName].length; + for (let i = 0; i < hl; i++) { + if (this._handlers[eventName][i] === handler) { + this._handlers[eventName].splice(i, 1); + return; + } + } + } + _emit(eventName, ...args) { + this._validateEvent(eventName); + this._handlers[eventName].slice().forEach((handler) => { + handler.apply(this, args); + }); + } + _validateEvent(eventName) { + if (!(eventName in this._handlers)) { + throw new Error("Unknown event: " + eventName); + } + } + _delegateEvent(eventName, target) { + target.on(eventName, (event) => { + this._emit(eventName, event); + }); + } + _addEvent(eventName) { + if (typeof this._handlers === 'undefined') { + this._handlers = {}; + } + this._handlers[eventName] = []; + } +} +module.exports = EventHandling; + + +/***/ }), + +/***/ "./src/features.ts": +/*!*************************!*\ + !*** ./src/features.ts ***! + \*************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const config_1 = __importDefault(__webpack_require__(/*! ./config */ "./src/config.ts")); +const env_1 = __importDefault(__webpack_require__(/*! ./env */ "./src/env.ts")); +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +const syncedgetputdelete_1 = __importDefault(__webpack_require__(/*! ./syncedgetputdelete */ "./src/syncedgetputdelete.ts")); +const access_1 = __importDefault(__webpack_require__(/*! ./access */ "./src/access.ts")); +const authorize_1 = __importDefault(__webpack_require__(/*! ./authorize */ "./src/authorize.ts")); +const discover_1 = __importDefault(__webpack_require__(/*! ./discover */ "./src/discover.ts")); +const baseclient_1 = __importDefault(__webpack_require__(/*! ./baseclient */ "./src/baseclient.ts")); +const googledrive_1 = __importDefault(__webpack_require__(/*! ./googledrive */ "./src/googledrive.ts")); +const dropbox_1 = __importDefault(__webpack_require__(/*! ./dropbox */ "./src/dropbox.ts")); +const wireclient_1 = __importDefault(__webpack_require__(/*! ./wireclient */ "./src/wireclient.ts")); +const sync_1 = __importDefault(__webpack_require__(/*! ./sync */ "./src/sync.ts")); +// Caching +const caching_1 = __importDefault(__webpack_require__(/*! ./caching */ "./src/caching.ts")); +const indexeddb_1 = __importDefault(__webpack_require__(/*! ./indexeddb */ "./src/indexeddb.ts")); +const localstorage_1 = __importDefault(__webpack_require__(/*! ./localstorage */ "./src/localstorage.ts")); +const inmemorystorage_1 = __importDefault(__webpack_require__(/*! ./inmemorystorage */ "./src/inmemorystorage.ts")); +const Features = { + features: [], + featuresDone: 0, + readyFired: false, + loadFeatures() { + this.features = []; + this.featuresDone = 0; + this.readyFired = false; + this.featureModules = { + 'WireClient': wireclient_1.default, + 'Dropbox': dropbox_1.default, + 'GoogleDrive': googledrive_1.default, + 'Access': access_1.default, + 'Discover': discover_1.default, + 'Authorize': authorize_1.default, + 'BaseClient': baseclient_1.default, + 'Env': env_1.default + }; + // enable caching related modules if needed + if (config_1.default.cache) { + // TODO replace util.extend with modern JS {...object, ...object} + (0, util_1.extend)(this.featureModules, { + 'Caching': caching_1.default, + 'IndexedDB': indexeddb_1.default, + 'LocalStorage': localstorage_1.default, + 'InMemoryStorage': inmemorystorage_1.default, + 'Sync': sync_1.default + }); + } + // disable features set in the config object passed to the RemoteStorage + // constructor + // For example: ['IndexedDB'] + config_1.default.disableFeatures.forEach(feature => { + if (this.featureModules[feature]) { + // this.featureModules[feature] = undefined + delete this.featureModules[feature]; + } + }); + this._allLoaded = false; + for (const featureName in this.featureModules) { + // FIXME: this has to push the promised return value into an + // array of promises and use Promise.all to emit `ready` + // instead of increment a counter of loaded features. -les + this.loadFeature(featureName); + } + }, + /** + * Method: hasFeature + * + * Checks whether a feature is enabled or not within remoteStorage. + * Returns a boolean. + * + * Parameters: + * name - Capitalized name of the feature. e.g. Authorize, or IndexedDB + * + * Example: + * (start code) + * if (remoteStorage.hasFeature('LocalStorage')) { + * console.log('LocalStorage is enabled!'); + * } + * (end code) + * + */ + hasFeature(feature) { + for (let i = this.features.length - 1; i >= 0; i--) { + if (this.features[i].name === feature) { + return this.features[i].supported; + } + } + return false; + }, + loadFeature(featureName) { + const feature = this.featureModules[featureName]; + const supported = !feature._rs_supported || feature._rs_supported(); + (0, log_1.default)(`[RemoteStorage] [FEATURE ${featureName}] initializing ...`); + if (typeof supported === 'object') { + supported.then(() => { + this.featureSupported(featureName, true); + this.initFeature(featureName); + }, () => { + this.featureSupported(featureName, false); + }); + } + else if (typeof supported === 'boolean') { + this.featureSupported(featureName, supported); + if (supported) { + this.initFeature(featureName); + } + } + else { + this.featureSupported(featureName, false); + } + }, + initFeature(featureName) { + const feature = this.featureModules[featureName]; + let initResult; + try { + initResult = feature._rs_init(this); + } + catch (e) { + this.featureFailed(featureName, e); + return; + } + if (typeof (initResult) === 'object' && typeof (initResult.then) === 'function') { + initResult.then(() => { this.featureInitialized(featureName); }, (err) => { this.featureFailed(featureName, err); }); + } + else { + this.featureInitialized(featureName); + } + }, + featureFailed(featureName, err) { + (0, log_1.default)(`[RemoteStorage] [FEATURE ${featureName}] initialization failed (${err})`); + this.featureDone(); + }, + featureSupported(featureName, success) { + (0, log_1.default)(`[RemoteStorage] [FEATURE ${featureName}]${success ? '' : 'not '} supported`); + if (!success) { + this.featureDone(); + } + }, + featureInitialized(featureName) { + (0, log_1.default)(`[RemoteStorage] [FEATURE ${featureName}] initialized`); + this.features.push({ + name: featureName, + init: this.featureModules[featureName]._rs_init, + supported: true, + cleanup: this.featureModules[featureName]._rs_cleanup + }); + this.featureDone(); + }, + featureDone() { + this.featuresDone++; + if (this.featuresDone === Object.keys(this.featureModules).length) { + setTimeout(this.featuresLoaded.bind(this), 0); + } + }, + _setCachingModule() { + const cachingModules = ['IndexedDB', 'LocalStorage', 'InMemoryStorage']; + cachingModules.some(cachingLayer => { + if (this.features.some(feature => feature.name === cachingLayer)) { + this.features.local = this.featureModules[cachingLayer]; + return true; + } + }); + }, + _fireReady() { + try { + if (!this.readyFired) { + this._emit('ready'); + this.readyFired = true; + } + } + catch (e) { + console.error("'ready' failed: ", e, e.stack); + this._emit('error', e); + } + }, + featuresLoaded() { + (0, log_1.default)(`[RemoteStorage] All features loaded`); + this._setCachingModule(); + // eslint-disable-next-line new-cap + this.local = config_1.default.cache && this.features.local && new this.features.local(); + // this.remote set by WireClient._rs_init as lazy property on + // RS.prototype + if (this.local && this.remote) { + this._setGPD(syncedgetputdelete_1.default, this); + this._bindChange(this.local); + } + else if (this.remote) { + this._setGPD(this.remote, this.remote); + } + if (this.remote) { + this.remote.on('connected', () => { + this._fireReady(); + this._emit('connected'); + }); + this.remote.on('not-connected', () => { + this._fireReady(); + this._emit('not-connected'); + }); + if (this.remote.connected) { + this._fireReady(); + this._emit('connected'); + } + if (!this.hasFeature('Authorize')) { + this.remote.stopWaitingForToken(); + } + } + this._collectCleanupFunctions(); + try { + this._allLoaded = true; + this._emit('features-loaded'); + } + catch (exc) { + (0, util_1.logError)(exc); + this._emit('error', exc); + } + this._processPending(); + }, + _collectCleanupFunctions() { + this._cleanups = []; + for (let i = 0; i < this.features.length; i++) { + const cleanup = this.features[i].cleanup; + if (typeof (cleanup) === 'function') { + this._cleanups.push(cleanup); + } + } + } +}; +module.exports = Features; + + +/***/ }), + +/***/ "./src/googledrive.ts": +/*!****************************!*\ + !*** ./src/googledrive.ts ***! + \****************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const baseclient_1 = __importDefault(__webpack_require__(/*! ./baseclient */ "./src/baseclient.ts")); +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +const requests_1 = __webpack_require__(/*! ./requests */ "./src/requests.ts"); +const remote_1 = __webpack_require__(/*! ./remote */ "./src/remote.ts"); +const BASE_URL = 'https://www.googleapis.com'; +const AUTH_URL = 'https://accounts.google.com/o/oauth2/auth'; +const AUTH_SCOPE = 'https://www.googleapis.com/auth/drive'; +const SETTINGS_KEY = 'remotestorage:googledrive'; +const PATH_PREFIX = '/remotestorage'; +const GD_DIR_MIME_TYPE = 'application/vnd.google-apps.folder'; +const RS_DIR_MIME_TYPE = 'application/json; charset=UTF-8'; +let hasLocalStorage; +/** + * Produce a title from a filename for metadata. + * + * @param {string} filename + * @returns {string} title + * + * @private + */ +function metaTitleFromFileName(filename) { + if (filename.substr(-1) === '/') { + filename = filename.substr(0, filename.length - 1); + } + return decodeURIComponent(filename); +} +/** + * Get the parent directory for the given path. + * + * @param {string} path + * @returns {string} parent directory + * + * @private + */ +function parentPath(path) { + return path.replace(/[^\/]+\/?$/, ''); +} +/** + * Get only the filename from a full path. + * + * @param {string} path + * @returns {string} filename + * + * @private + */ +function baseName(path) { + const parts = path.split('/'); + if (path.substr(-1) === '/') { + return parts[parts.length - 2] + '/'; + } + else { + return parts[parts.length - 1]; + } +} +/** + * Prepend the path with the remoteStorage base directory. + * + * @param {string} path - Path + * @returns {string} Actual path on Google Drive + * + * @private + */ +function googleDrivePath(path) { + return (0, util_1.cleanPath)(`${PATH_PREFIX}/${path}`); +} +/** + * Internal cache object for storing Google file IDs. + * + * @param {number} maxAge - Maximum age (in seconds) the content should be cached for + */ +class FileIdCache { + constructor(maxAge) { + this._items = {}; + this.maxAge = maxAge; + this._items = {}; + } + get(key) { + const item = this._items[key]; + const now = new Date().getTime(); + return (item && item.t >= (now - this.maxAge)) ? item.v : undefined; + } + set(key, value) { + this._items[key] = { + v: value, + t: new Date().getTime() + }; + } +} +/** + * Overwrite BaseClient's getItemURL with our own implementation + * + * TODO: Still needs to be implemented. At the moment it just throws + * and error saying that it's not implemented yet. + * + * @param {object} rs - RemoteStorage instance + * + * @private + */ +function hookGetItemURL(rs) { + if (rs._origBaseClientGetItemURL) { + return; + } + rs._origBaseClientGetItemURL = baseclient_1.default.prototype.getItemURL; + baseclient_1.default.prototype.getItemURL = function ( /* path */) { + throw new Error('getItemURL is not implemented for Google Drive yet'); + }; +} +/** + * Restore BaseClient's getItemURL original implementation + * + * @param {object} rs - RemoteStorage instance + * + * @private + */ +function unHookGetItemURL(rs) { + if (!rs._origBaseClientGetItemURL) { + return; + } + baseclient_1.default.prototype.getItemURL = rs._origBaseClientGetItemURL; + delete rs._origBaseClientGetItemURL; +} +/** + * @class GoogleDrive + * + * To use this backend, you need to specify the app's client ID like so: + * + * @example + * remoteStorage.setApiKeys({ + * googledrive: 'your-client-id' + * }); + * + * A client ID can be obtained by registering your app in the Google + * Developers Console: https://console.developers.google.com/flows/enableapi?apiid=drive + * + * Docs: https://developers.google.com/drive/v3/web/quickstart/js +**/ +class GoogleDrive extends remote_1.RemoteBase { + constructor(remoteStorage, clientId) { + super(remoteStorage); + this.online = true; + this.storageApi = 'draft-dejong-remotestorage-19'; + this.addEvents(['connected', 'not-connected']); + this.clientId = clientId; + this._fileIdCache = new FileIdCache(60 * 5); // IDs expire after 5 minutes (is this a good idea?) + hasLocalStorage = (0, util_1.localStorageAvailable)(); + if (hasLocalStorage) { + const settings = (0, util_1.getJSONFromLocalStorage)(SETTINGS_KEY); + if (settings) { + this.configure(settings); + } + } + } + /** + * Configure the Google Drive backend. + * + * Fetches the user info from Google when no ``userAddress`` is given. + * + * @param {Object} settings + * @param {string} [settings.userAddress] - The user's email address + * @param {string} [settings.token] - Authorization token + * + * @protected + */ + configure(settings) { + // We only update this.userAddress if settings.userAddress is set to a string or to null + if (typeof settings.userAddress !== 'undefined') { + this.userAddress = settings.userAddress; + } + // Same for this.token. If only one of these two is set, we leave the other one at its existing value + if (typeof settings.token !== 'undefined') { + this.token = settings.token; + } + const writeSettingsToCache = function () { + if (hasLocalStorage) { + localStorage.setItem(SETTINGS_KEY, JSON.stringify({ + userAddress: this.userAddress, + token: this.token + })); + } + }; + const handleError = function () { + this.connected = false; + delete this.token; + if (hasLocalStorage) { + localStorage.removeItem(SETTINGS_KEY); + } + }; + if (this.token) { + this.connected = true; + if (this.userAddress) { + this._emit('connected'); + writeSettingsToCache.apply(this); + } + else { + this.info().then((info) => { + this.userAddress = info.user.emailAddress; + this._emit('connected'); + writeSettingsToCache.apply(this); + }).catch(() => { + handleError.apply(this); + this.rs._emit('error', new Error('Could not fetch user info.')); + }); + } + } + else { + handleError.apply(this); + } + } + /** + * Initiate the authorization flow's OAuth dance. + */ + connect() { + this.rs.setBackend('googledrive'); + this.rs.authorize({ authURL: AUTH_URL, scope: AUTH_SCOPE, clientId: this.clientId }); + } + /** + * Request a resource (file or directory). + * + * @param {string} path - Path of the resource + * @param {Object} options - Request options + * @returns {Promise} Resolves with an object containing the status code, + * body, content-type and revision + * + * @protected + */ + get(path, options = {}) { + if ((0, util_1.isFolder)(path)) { + return this._getFolder(googleDrivePath(path)); + } + else { + return this._getFile(googleDrivePath(path), options); + } + } + /** + * Create or update a file. + * + * @param {string} path - File path + * @param body - File content + * @param {string} contentType - File content-type + * @param {Object} options + * @param {string} options.ifNoneMatch - Only create of update the file if the + * current ETag doesn't match this string + * @returns {Promise} Resolves with an object containing the status code, + * content-type and revision + * + * @protected + */ + put(path, body, contentType, options = {}) { + const fullPath = googleDrivePath(path); + function putDone(response) { + if (response.status >= 200 && response.status < 300) { + const meta = JSON.parse(response.responseText); + const etagWithoutQuotes = this.stripQuotes(meta.etag); + return Promise.resolve({ statusCode: 200, contentType: meta.mimeType, revision: etagWithoutQuotes }); + } + else if (response.status === 412) { + return Promise.resolve({ statusCode: 412, revision: 'conflict' }); + } + else { + return Promise.reject("PUT failed with status " + response.status + " (" + response.responseText + ")"); + } + } + return this._getFileId(fullPath).then((id) => { + if (id) { + if (options && (options.ifNoneMatch === '*')) { + return putDone({ status: 412 }); + } + return this._updateFile(id, fullPath, body, contentType, options).then(putDone); + } + else { + return this._createFile(fullPath, body, contentType).then(putDone); + } + }); + } + /** + * Delete a file. + * + * @param {string} path - File path + * @param {Object} options + * @param {string} options.ifMatch - only delete the file if it's ETag + * matches this string + * @returns {Promise} Resolves with an object containing the status code + * + * @protected + */ + delete(path, options = {}) { + const fullPath = googleDrivePath(path); + return this._getFileId(fullPath).then((id) => { + if (!id) { + // File doesn't exist. Ignore. + return Promise.resolve({ statusCode: 200 }); + } + return this._getMeta(id).then((meta) => { + let etagWithoutQuotes; + if ((typeof meta === 'object') && (typeof meta.etag === 'string')) { + etagWithoutQuotes = this.stripQuotes(meta.etag); + } + if (options && options.ifMatch && (options.ifMatch !== etagWithoutQuotes)) { + return { statusCode: 412, revision: etagWithoutQuotes }; + } + return this._request('DELETE', BASE_URL + '/drive/v2/files/' + id, {}).then((response) => { + if (response.status === 200 || response.status === 204) { + return { statusCode: 200 }; + } + else { + return Promise.reject("Delete failed: " + response.status + " (" + response.responseText + ")"); + } + }); + }); + }); + } + /** + * Fetch the user's info from Google. + * + * @returns {Promise} resolves with the user's info. + * + * @protected + */ + info() { + const url = BASE_URL + '/drive/v2/about?fields=user'; + // requesting user info(mainly for userAdress) + return this._request('GET', url, {}).then(function (resp) { + try { + const info = JSON.parse(resp.responseText); + return Promise.resolve(info); + } + catch (e) { + return Promise.reject(e); + } + }); + } + /** + * Update an existing file. + * + * @param {string} id - File ID + * @param {string} path - File path + * @param body - File content + * @param {string} contentType - File content-type + * @param {Object} options + * @param {string} options.ifMatch - Only update the file if its ETag + * matches this string + * @returns {Promise} Resolves with the response of the network request + * + * @private + */ + _updateFile(id, path, body, contentType, options) { + const metadata = { + mimeType: contentType + }; + const headers = { + 'Content-Type': 'application/json; charset=UTF-8' + }; + if (options && options.ifMatch) { + headers['If-Match'] = this.addQuotes(options.ifMatch); + } + return this._request('PUT', BASE_URL + '/upload/drive/v2/files/' + id + '?uploadType=resumable', { + body: JSON.stringify(metadata), + headers: headers + }).then((response) => { + if (response.status === 412) { + return (response); + } + else { + return this._request('PUT', response.getResponseHeader('Location'), { + body: contentType.match(/^application\/json/) ? JSON.stringify(body) : body + }); + } + }); + } + /** + * Create a new file. + * + * @param {string} path - File path + * @param body - File content + * @param {string} contentType - File content-type + * @returns {Promise} Resolves with the response of the network request + * + * @private + */ + _createFile(path, body, contentType) { + return this._getParentId(path).then((parentId) => { + const fileName = baseName(path); + const metadata = { + title: metaTitleFromFileName(fileName), + mimeType: contentType, + parents: [{ + kind: "drive#fileLink", + id: parentId + }] + }; + return this._request('POST', BASE_URL + '/upload/drive/v2/files?uploadType=resumable', { + body: JSON.stringify(metadata), + headers: { + 'Content-Type': 'application/json; charset=UTF-8' + } + }).then((response) => { + return this._request('POST', response.getResponseHeader('Location'), { + body: contentType.match(/^application\/json/) ? JSON.stringify(body) : body + }); + }); + }); + } + /** + * Request a file. + * + * @param {string} path - File path + * @param {Object} options + * @param {string} [options.ifNoneMath] - Only return the file if its ETag + * doesn't match the given string + * @returns {Promise} Resolves with an object containing the status code, + * body, content-type and revision + * + * @private + */ + _getFile(path, options) { + return this._getFileId(path).then((id) => { + return this._getMeta(id).then((meta) => { + let etagWithoutQuotes; + if (typeof (meta) === 'object' && typeof (meta.etag) === 'string') { + etagWithoutQuotes = this.stripQuotes(meta.etag); + } + if (options && options.ifNoneMatch && (etagWithoutQuotes === options.ifNoneMatch)) { + return Promise.resolve({ statusCode: 304 }); + } + if (!meta.downloadUrl) { + if (meta.exportLinks && meta.exportLinks['text/html']) { + // Documents that were generated inside GoogleDocs have no + // downloadUrl, but you can export them to text/html instead: + meta.mimeType += ';export=text/html'; + meta.downloadUrl = meta.exportLinks['text/html']; + } + else { + // empty file + return Promise.resolve({ statusCode: 200, body: '', contentType: meta.mimeType, revision: etagWithoutQuotes }); + } + } + const params = { + responseType: 'arraybuffer' + }; + return this._request('GET', meta.downloadUrl, params).then((response) => { + //first encode the response as text, and later check if + //text appears to actually be binary data + return (0, util_1.getTextFromArrayBuffer)(response.response, 'UTF-8').then(function (responseText) { + let body = responseText; + if (meta.mimeType.match(/^application\/json/)) { + try { + body = JSON.parse(body); + } + catch (e) { + // body couldn't be parsed as JSON, so we'll just return it as is + } + } + else if ((0, util_1.shouldBeTreatedAsBinary)(responseText, meta.mimeType)) { + //return unprocessed response + body = response.response; + } + return { + statusCode: 200, + body: body, + contentType: meta.mimeType, + revision: etagWithoutQuotes + }; + }); + }); + }); + }); + } + /** + * Request a directory. + * + * @param {string} path - Directory path + * @returns {Promise} Resolves with an object containing the status code, + * body and content-type + * + * @private + */ + _getFolder(path) { + return this._getFileId(path).then((id) => { + let data, etagWithoutQuotes, itemsMap; + if (!id) { + return Promise.resolve({ statusCode: 404 }); + } + const query = '\'' + id + '\' in parents'; + const fields = 'items(downloadUrl,etag,fileSize,id,mimeType,title,labels)'; + return this._request('GET', BASE_URL + '/drive/v2/files?' + + 'q=' + encodeURIComponent(query) + + '&fields=' + encodeURIComponent(fields) + + '&maxResults=1000' + + '&trashed=false', {}) + .then((response) => { + var _a; + if (response.status !== 200) { + return Promise.reject('request failed or something: ' + response.status); + } + try { + data = JSON.parse(response.responseText); + } + catch (e) { + return Promise.reject('non-JSON response from GoogleDrive'); + } + itemsMap = {}; + for (const item of data.items) { + if ((_a = item.labels) === null || _a === void 0 ? void 0 : _a.trashed) { + continue; + } // ignore deleted files + etagWithoutQuotes = this.stripQuotes(item.etag); + if (item.mimeType === GD_DIR_MIME_TYPE) { + this._fileIdCache.set(path + (0, util_1.cleanPath)(item.title) + '/', item.id); + itemsMap[item.title + '/'] = { + ETag: etagWithoutQuotes + }; + } + else { + this._fileIdCache.set(path + (0, util_1.cleanPath)(item.title), item.id); + itemsMap[item.title] = { + ETag: etagWithoutQuotes, + 'Content-Type': item.mimeType, + 'Content-Length': item.fileSize + }; + } + } + // FIXME: add revision of folder! + return Promise.resolve({ statusCode: 200, body: itemsMap, contentType: RS_DIR_MIME_TYPE, revision: undefined }); + }); + }); + } + /** + * Get the ID of a parent path. + * + * Creates the directory if it doesn't exist yet. + * + * @param {string} path - Full path of a directory or file + * @returns {Promise} Resolves with ID of the parent directory. + * + * @private + */ + _getParentId(path) { + const foldername = parentPath(path); + return this._getFileId(foldername).then((parentId) => { + if (parentId) { + return Promise.resolve(parentId); + } + else { + return this._createFolder(foldername); + } + }); + } + /** + * Create a directory. + * + * Creates all parent directories as well if any of them didn't exist yet. + * + * @param {string} path - Directory path + * @returns {Promise} Resolves with the ID of the new directory + * + * @private + */ + _createFolder(path) { + return this._getParentId(path).then((parentId) => { + return this._request('POST', BASE_URL + '/drive/v2/files', { + body: JSON.stringify({ + title: metaTitleFromFileName(baseName(path)), + mimeType: GD_DIR_MIME_TYPE, + parents: [{ + id: parentId + }] + }), + headers: { + 'Content-Type': 'application/json; charset=UTF-8' + } + }).then((response) => { + const meta = JSON.parse(response.responseText); + return Promise.resolve(meta.id); + }); + }); + } + /** + * Get the ID of a file. + * + * @param {string} path - File path + * @returns {Promise} Resolves with the ID + * + * @private + */ + _getFileId(path) { + let id; + if (path === '/') { + // "root" is a special alias for the fileId of the root folder + return Promise.resolve('root'); + } + else if ((id = this._fileIdCache.get(path))) { + // id is cached. + return Promise.resolve(id); + } + // id is not cached (or file doesn't exist). + // load parent folder listing to propagate / update id cache. + return this._getFolder(parentPath(path)).then(() => { + id = this._fileIdCache.get(path); + if (!id) { + if (path.substr(-1) === '/') { + return this._createFolder(path).then(() => { + return this._getFileId(path); + }); + } + else { + return Promise.resolve(); + } + } + return Promise.resolve(id); + }); + } + /** + * Get the metadata for a given file ID. + * + * @param {string} id - File ID + * @returns {Promise} Resolves with an object containing the metadata + * + * @private + */ + _getMeta(id) { + return this._request('GET', BASE_URL + '/drive/v2/files/' + id, {}).then(function (response) { + if (response.status === 200) { + return Promise.resolve(JSON.parse(response.responseText)); + } + else { + return Promise.reject("request (getting metadata for " + id + ") failed with status: " + response.status); + } + }); + } + /** + * Make a network request. + * + * @param {string} method - Request method + * @param {string} url - Target URL + * @param {Object} options - Request options + * @returns {Promise} Resolves with the response of the network request + * + * @private + */ + _request(method, url, options) { + if (this.isForbiddenRequestMethod(method, url)) { + return Promise.reject(`Don't use ${method} on directories!`); + } + if (!options.headers) { + options.headers = {}; + } + options.headers['Authorization'] = 'Bearer ' + this.token; + this.rs._emit('wire-busy', { + method: method, + isFolder: (0, util_1.isFolder)(url) + }); + return (0, requests_1.requestWithTimeout)(method, url, options).then((xhr) => { + // Google tokens expire from time to time... + if (xhr && xhr.status === 401) { + this.connect(); + return; + } + else { + if (!this.online) { + this.online = true; + this.rs._emit('network-online'); + } + this.rs._emit('wire-done', { + method: method, + isFolder: (0, util_1.isFolder)(url), + success: true + }); + return Promise.resolve(xhr); + } + }, (error) => { + if (this.online) { + this.online = false; + this.rs._emit('network-offline'); + } + this.rs._emit('wire-done', { + method: method, + isFolder: (0, util_1.isFolder)(url), + success: false + }); + return Promise.reject(error); + }); + } + /** + * Initialize the Google Drive backend. + * + * @param {Object} remoteStorage - RemoteStorage instance + * + * @protected + */ + static _rs_init(remoteStorage) { + const config = remoteStorage.apiKeys.googledrive; + if (config) { + remoteStorage.googledrive = new GoogleDrive(remoteStorage, config.clientId); + if (remoteStorage.backend === 'googledrive') { + remoteStorage._origRemote = remoteStorage.remote; + remoteStorage.remote = remoteStorage.googledrive; + hookGetItemURL(remoteStorage); + } + } + } + /** + * Inform about the availability of the Google Drive backend. + * + * @returns {Boolean} + * + * @protected + */ + static _rs_supported() { + return true; + } + /** + * Remove Google Drive as a backend. + * + * @param {Object} remoteStorage - RemoteStorage instance + * + * @protected + */ + static _rs_cleanup(remoteStorage) { + remoteStorage.setBackend(undefined); + if (remoteStorage._origRemote) { + remoteStorage.remote = remoteStorage._origRemote; + delete remoteStorage._origRemote; + } + unHookGetItemURL(remoteStorage); + } +} +(0, util_1.applyMixins)(GoogleDrive, [eventhandling_1.default]); +module.exports = GoogleDrive; + + +/***/ }), + +/***/ "./src/indexeddb.ts": +/*!**************************!*\ + !*** ./src/indexeddb.ts ***! + \**************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) { +/** + * TODO rewrite, doesn't expose GPD anymore, it's in cachinglayer now + * + * This file exposes a get/put/delete interface, accessing data in an IndexedDB. + * + * There are multiple parts to this interface: + * + * The RemoteStorage integration: + * - IndexedDB._rs_supported() determines if IndexedDB support + * is available. If it isn't, RemoteStorage won't initialize the feature. + * - IndexedDB._rs_init() initializes the feature. It returns + * a promise that is fulfilled as soon as the database has been opened and + * migrated. + * + * The storage interface (IndexedDB object): + * - Usually this is accessible via "remoteStorage.local" + * - #get() takes a path and returns a promise. + * - #put() takes a path, body and contentType and also returns a promise. + * - #delete() takes a path and also returns a promise. + * - #on('change', ...) events, being fired whenever something changes in + * the storage. Change events roughly follow the StorageEvent pattern. + * They have "oldValue" and "newValue" properties, which can be used to + * distinguish create/update/delete operations and analyze changes in + * change handlers. In addition they carry a "origin" property, which + * is either "window", "local", or "remote". "remote" events are fired + * whenever a change comes in from Sync. + * + * The sync interface (also on IndexedDB object): + * - #getNodes([paths]) returns the requested nodes in a promise. + * - #setNodes(map) stores all the nodes given in the (path -> node) map. + * + * @interface + */ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const cachinglayer_1 = __importDefault(__webpack_require__(/*! ./cachinglayer */ "./src/cachinglayer.ts")); +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +const DB_VERSION = 2; +const DEFAULT_DB_NAME = 'remotestorage'; +// TODO very weird that this is re-assigned +let DEFAULT_DB; +class IndexedDB extends cachinglayer_1.default { + constructor(database) { + super(); + this.addEvents(['change', 'local-events-done']); + this.db = database || DEFAULT_DB; + if (!this.db) { + // TODO shouldn't this throw an error? + (0, log_1.default)("[IndexedDB] Failed to open DB"); + return undefined; + } + this.getsRunning = 0; + this.putsRunning = 0; + /** + * Given a node for which uncommitted changes exist, this cache + * stores either the entire uncommitted node, or false for a deletion. + * The node's path is used as the key. + * + * changesQueued stores changes for which no IndexedDB transaction has + * been started yet. + */ + this.changesQueued = {}; + /** + * Given a node for which uncommitted changes exist, this cache + * stores either the entire uncommitted node, or false for a deletion. + * The node's path is used as the key. + * + * At any time there is at most one IndexedDB transaction running. + * changesRunning stores the changes that are included in that currently + * running IndexedDB transaction, or if none is running, of the last one + * that ran. + */ + this.changesRunning = {}; + // TODO document + this.commitSlownessWarning = null; + } + /** + * TODO: Document + */ + getNodes(paths) { + return __awaiter(this, void 0, void 0, function* () { + const misses = [], fromCache = {}; + for (let i = 0, len = paths.length; i < len; i++) { + if (this.changesQueued[paths[i]] !== undefined) { + fromCache[paths[i]] = (0, util_1.deepClone)(this.changesQueued[paths[i]] || undefined); + } + else if (this.changesRunning[paths[i]] !== undefined) { + fromCache[paths[i]] = (0, util_1.deepClone)(this.changesRunning[paths[i]] || undefined); + } + else { + misses.push(paths[i]); + } + } + if (misses.length > 0) { + return this.getNodesFromDb(misses).then(function (nodes) { + for (const i in fromCache) { + nodes[i] = fromCache[i]; + } + return nodes; + }); + } + else { + return Promise.resolve(fromCache); + } + }); + } + /** + * TODO: Document + */ + setNodes(nodes) { + return __awaiter(this, void 0, void 0, function* () { + for (const i in nodes) { + this.changesQueued[i] = nodes[i] || false; + } + this.maybeFlush(); + return Promise.resolve(); + }); + } + /** + * TODO: Document + */ + maybeFlush() { + if (this.putsRunning === 0) { + this.flushChangesQueued(); + } + else { + if (!this.commitSlownessWarning) { + this.commitSlownessWarning = global.setInterval(function () { + console.warn('WARNING: waited more than 10 seconds for previous commit to finish'); + }, 10000); + } + } + } + /** + * TODO: Document + */ + flushChangesQueued() { + if (this.commitSlownessWarning) { + clearInterval(this.commitSlownessWarning); + this.commitSlownessWarning = null; + } + if (Object.keys(this.changesQueued).length > 0) { + this.changesRunning = this.changesQueued; + this.changesQueued = {}; + this.setNodesInDb(this.changesRunning).then(this.flushChangesQueued.bind(this)); + } + } + /** + * TODO: Document + */ + getNodesFromDb(paths) { + return new Promise((resolve, reject) => { + const transaction = this.db.transaction(['nodes'], 'readonly'); + const nodes = transaction.objectStore('nodes'); + const retrievedNodes = {}; + this.getsRunning++; + paths.map((path) => { + nodes.get(path).onsuccess = (evt) => { + retrievedNodes[path] = evt.target.result; + }; + }); + transaction.oncomplete = () => { + resolve(retrievedNodes); + this.getsRunning--; + }; + transaction.onerror = transaction.onabort = () => { + reject('get transaction error/abort'); + this.getsRunning--; + }; + }); + } + /** + * TODO: Document + */ + setNodesInDb(nodes) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + const transaction = this.db.transaction(['nodes'], 'readwrite'); + const nodesStore = transaction.objectStore('nodes'); + const startTime = new Date().getTime(); + this.putsRunning++; + (0, log_1.default)('[IndexedDB] Starting put', nodes, this.putsRunning); + for (const path in nodes) { + const node = nodes[path]; + if (typeof (node) === 'object') { + try { + nodesStore.put(node); + } + catch (e) { + (0, log_1.default)('[IndexedDB] Error while putting', node, e); + throw e; + } + } + else { + try { + nodesStore.delete(path); + } + catch (e) { + (0, log_1.default)('[IndexedDB] Error while removing', nodesStore, node, e); + throw e; + } + } + } + transaction.oncomplete = () => { + this.putsRunning--; + (0, log_1.default)('[IndexedDB] Finished put', nodes, this.putsRunning, (new Date().getTime() - startTime) + 'ms'); + resolve(); + }; + transaction.onerror = () => { + this.putsRunning--; + reject('transaction error'); + }; + transaction.onabort = () => { + reject('transaction abort'); + this.putsRunning--; + }; + }); + }); + } + /** + * TODO: Document + */ + // TODO add real types once known + reset(callback) { + const dbName = this.db.name; + this.db.close(); + IndexedDB.clean(this.db.name, () => { + IndexedDB.open(dbName, (err, other) => { + if (err) { + (0, log_1.default)('[IndexedDB] Error while resetting local storage', err); + } + else { + // hacky! + this.db = other; + } + if (typeof callback === 'function') { + callback(self); + } + }); + }); + } + /** + * TODO: Document + */ + forAllNodes(cb) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve /*, reject*/) => { + const transaction = this.db.transaction(['nodes'], 'readonly'); + const cursorReq = transaction.objectStore('nodes').openCursor(); + cursorReq.onsuccess = (evt) => { + const cursor = evt.target.result; + if (cursor) { + cb(this.migrate(cursor.value)); + cursor.continue(); + } + else { + resolve(); + } + }; + }); + }); + } + closeDB() { + if (this.putsRunning === 0) { // check if we are currently writing to the DB + this.db.close(); + } + else { + setTimeout(this.closeDB.bind(this), 100); // try again a little later + } + } + /** + * TODO: Document + */ + // TODO add real types once known + static open(name, callback) { + const timer = setTimeout(function () { + callback("timeout trying to open db"); + }, 10000); + try { + const req = indexedDB.open(name, DB_VERSION); + req.onerror = function () { + (0, log_1.default)('[IndexedDB] Opening DB failed', req); + clearTimeout(timer); + callback(req.error); + }; + req.onupgradeneeded = function (event) { + const db = req.result; + (0, log_1.default)("[IndexedDB] Upgrade: from ", event.oldVersion, " to ", event.newVersion); + if (event.oldVersion !== 1) { + (0, log_1.default)("[IndexedDB] Creating object store: nodes"); + db.createObjectStore('nodes', { keyPath: 'path' }); + } + (0, log_1.default)("[IndexedDB] Creating object store: changes"); + db.createObjectStore('changes', { keyPath: 'path' }); + }; + req.onsuccess = function () { + clearTimeout(timer); + // check if all object stores exist + const db = req.result; + if (!db.objectStoreNames.contains('nodes') || !db.objectStoreNames.contains('changes')) { + (0, log_1.default)("[IndexedDB] Missing object store. Resetting the database."); + IndexedDB.clean(name, function () { + IndexedDB.open(name, callback); + }); + return; + } + callback(null, req.result); + }; + } + catch (error) { + (0, log_1.default)("[IndexedDB] Failed to open database: " + error); + (0, log_1.default)("[IndexedDB] Resetting database and trying again."); + clearTimeout(timer); + IndexedDB.clean(name, function () { + IndexedDB.open(name, callback); + }); + } + } + /** + * TODO: Document + */ + static clean(databaseName, callback) { + const req = indexedDB.deleteDatabase(databaseName); + req.onsuccess = function () { + (0, log_1.default)('[IndexedDB] Done removing DB'); + callback(); + }; + // TODO check if this does anything as onabort does not exist on type according to ts + req.onerror = req.onabort = function (evt) { + console.error('Failed to remove database "' + databaseName + '"', evt); + }; + } + /** + * Initialize the IndexedDB backend. + * + * @param {Object} remoteStorage - RemoteStorage instance + * + * @protected + */ + // TODO add real type once known + static _rs_init(remoteStorage) { + return new Promise((resolve, reject) => { + IndexedDB.open(DEFAULT_DB_NAME, function (err, db) { + if (err) { + reject(err); + } + else { + DEFAULT_DB = db; + // TODO remove once real type once known + db.onerror = () => { + remoteStorage._emit('error', err); + }; + resolve(); + } + }); + }); + } + /** + * Inform about the availability of the IndexedDB backend. + * + * @param {Object} rs - RemoteStorage instance + * @returns {Boolean} + * + * @protected + */ + static _rs_supported() { + return new Promise((resolve, reject) => { + const context = (0, util_1.getGlobalContext)(); + // FIXME: this is causing an error in chrome + // context.indexedDB = context.indexedDB || context.webkitIndexedDB || + // context.mozIndexedDB || context.oIndexedDB || + // context.msIndexedDB; + // Detect browsers with known IndexedDb issues (e.g. Android pre-4.4) + let poorIndexedDbSupport = false; + if (typeof navigator !== 'undefined' && + navigator.userAgent.match(/Android (2|3|4\.[0-3])/)) { + // Chrome and Firefox support IndexedDB + if (!navigator.userAgent.match(/Chrome|Firefox/)) { + poorIndexedDbSupport = true; + } + } + if ('indexedDB' in context && !poorIndexedDbSupport) { + try { + const check = indexedDB.open("rs-check"); + check.onerror = function ( /* event */) { + reject(); + }; + check.onsuccess = function ( /* event */) { + check.result.close(); + indexedDB.deleteDatabase("rs-check"); + resolve(); + }; + } + catch (e) { + reject(); + } + } + else { + reject(); + } + }); + } + /** + * Remove IndexedDB as a backend. + * + * @param {Object} remoteStorage - RemoteStorage instance + * + * @protected + */ + static _rs_cleanup(remoteStorage) { + return new Promise((resolve /*, reject*/) => { + if (remoteStorage.local) { + remoteStorage.local.closeDB(); + } + IndexedDB.clean(DEFAULT_DB_NAME, resolve); + }); + } + diffHandler() { + // empty + } +} +(0, util_1.applyMixins)(IndexedDB, [eventhandling_1.default]); +module.exports = IndexedDB; + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../node_modules/webpack/buildin/global.js */ "./node_modules/webpack/buildin/global.js"))) + +/***/ }), + +/***/ "./src/inmemorystorage.ts": +/*!********************************!*\ + !*** ./src/inmemorystorage.ts ***! + \********************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const cachinglayer_1 = __importDefault(__webpack_require__(/*! ./cachinglayer */ "./src/cachinglayer.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +/** + * In-memory caching adapter. Used when no IndexedDB or localStorage + * available. + * + * @class + **/ +class InMemoryStorage extends cachinglayer_1.default { + constructor() { + super(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this._storage = {}; + this.addEvents(['change', 'local-events-done']); + } + getNodes(paths) { + const nodes = {}; + for (let i = 0, len = paths.length; i < len; i++) { + nodes[paths[i]] = this._storage[paths[i]]; + } + return Promise.resolve(nodes); + } + setNodes(nodes) { + for (const path in nodes) { + if (nodes[path] === undefined) { + delete this._storage[path]; + } + else { + this._storage[path] = nodes[path]; + } + } + return Promise.resolve(); + } + forAllNodes(cb) { + for (const path in this._storage) { + cb(this.migrate(this._storage[path])); + } + return Promise.resolve(); + } + diffHandler() { + // empty + } + /** + * Initialize the InMemoryStorage backend. + * + * @param {Object} remoteStorage - RemoteStorage instance + * + * @protected + */ + static _rs_init() { + // empty + } + /** + * Inform about the availability of the InMemoryStorage backend. + * + * @returns {Boolean} + * + * @protected + */ + static _rs_supported() { + // In-memory storage is always supported + return true; + } + /** + * Remove InMemoryStorage as a backend. + * + * @protected + */ + static _rs_cleanup() { + // empty + } +} +(0, util_1.applyMixins)(InMemoryStorage, [eventhandling_1.default]); +module.exports = InMemoryStorage; + + +/***/ }), + +/***/ "./src/localstorage.ts": +/*!*****************************!*\ + !*** ./src/localstorage.ts ***! + \*****************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const cachinglayer_1 = __importDefault(__webpack_require__(/*! ./cachinglayer */ "./src/cachinglayer.ts")); +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +/** + * localStorage caching adapter. Used when no IndexedDB available. + **/ +const NODES_PREFIX = "remotestorage:cache:nodes:"; +const CHANGES_PREFIX = "remotestorage:cache:changes:"; +function isRemoteStorageKey(key) { + return key.substr(0, NODES_PREFIX.length) === NODES_PREFIX || + key.substr(0, CHANGES_PREFIX.length) === CHANGES_PREFIX; +} +function isNodeKey(key) { + return key.substr(0, NODES_PREFIX.length) === NODES_PREFIX; +} +class LocalStorage extends cachinglayer_1.default { + constructor() { + super(); + this.addEvents(['change', 'local-events-done']); + } + // TODO fix this + diffHandler(...args) { + return; + } + getNodes(paths) { + const nodes = {}; + for (let i = 0, len = paths.length; i < len; i++) { + try { + nodes[paths[i]] = JSON.parse(localStorage[NODES_PREFIX + paths[i]]); + } + catch (e) { + nodes[paths[i]] = undefined; + } + } + return Promise.resolve(nodes); + } + setNodes(nodes) { + for (const path in nodes) { + // TODO shouldn't we use getItem/setItem? + localStorage[NODES_PREFIX + path] = JSON.stringify(nodes[path]); + } + return Promise.resolve(); + } + forAllNodes(cb) { + let node; + for (let i = 0, len = localStorage.length; i < len; i++) { + if (isNodeKey(localStorage.key(i))) { + try { + // NOTE: this is coming from caching layer todo fix via interface or similar + node = this.migrate(JSON.parse(localStorage[localStorage.key(i)])); + } + catch (e) { + node = undefined; + } + if (node) { + cb(node); + } + } + } + return Promise.resolve(); + } + /** + * Initialize the LocalStorage backend. + * + * @protected + */ + static _rs_init() { + return; + } + /** + * Inform about the availability of the LocalStorage backend. + * + * @protected + */ + static _rs_supported() { + return (0, util_1.localStorageAvailable)(); + } + /** + * Remove LocalStorage as a backend. + * + * @protected + * + * TODO: tests missing! + */ + static _rs_cleanup() { + const keys = []; + for (let i = 0, len = localStorage.length; i < len; i++) { + const key = localStorage.key(i); + if (isRemoteStorageKey(key)) { + keys.push(key); + } + } + keys.forEach((key) => { + (0, log_1.default)('[LocalStorage] Removing', key); + delete localStorage[key]; + }); + } +} +(0, util_1.applyMixins)(LocalStorage, [eventhandling_1.default]); +module.exports = LocalStorage; + + +/***/ }), + +/***/ "./src/log.ts": +/*!********************!*\ + !*** ./src/log.ts ***! + \********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const config_1 = __importDefault(__webpack_require__(/*! ./config */ "./src/config.ts")); +/** + * Log using console.log, when remoteStorage logging is enabled. + * + * You can enable logging with ``RemoteStorage#enableLog``. + * + * (You can also enable logging during remoteStorage object creation. See: + * {@link RemoteStorage}). + */ +function log(...args) { + if (config_1.default.logging) { + // eslint-disable-next-line no-console + console.log(...args); + } +} +module.exports = log; + + +/***/ }), + +/***/ "./src/remote.ts": +/*!***********************!*\ + !*** ./src/remote.ts ***! + \***********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.RemoteBase = void 0; +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +/** + * The ancestor for WireClient, GoogleDrive & Dropbox + */ +class RemoteBase extends eventhandling_1.default { + constructor(rs) { + super(); + this.rs = rs; + this.connected = false; + // TODO: Should `online` be set true or false for all, here or in configure? + } + stopWaitingForToken() { + if (!this.connected) { + this._emit('not-connected'); + } + } + addQuotes(str) { + if (typeof (str) !== 'string') { + return str; + } + if (str === '*') { + return '*'; + } + return '"' + str + '"'; + } + stripQuotes(str) { + if (typeof (str) !== 'string') { + return str; + } + return str.replace(/^["']|["']$/g, ''); + } + isForbiddenRequestMethod(method, uri) { + if (method === 'PUT' || method === 'DELETE') { + return (0, util_1.isFolder)(uri); + } + else { + return false; + } + } +} +exports.RemoteBase = RemoteBase; + + +/***/ }), + +/***/ "./src/remotestorage.ts": +/*!******************************!*\ + !*** ./src/remotestorage.ts ***! + \******************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const config_1 = __importDefault(__webpack_require__(/*! ./config */ "./src/config.ts")); +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +const access_1 = __importDefault(__webpack_require__(/*! ./access */ "./src/access.ts")); +const authorize_1 = __importDefault(__webpack_require__(/*! ./authorize */ "./src/authorize.ts")); +const baseclient_1 = __importDefault(__webpack_require__(/*! ./baseclient */ "./src/baseclient.ts")); +const caching_1 = __importDefault(__webpack_require__(/*! ./caching */ "./src/caching.ts")); +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const googledrive_1 = __importDefault(__webpack_require__(/*! ./googledrive */ "./src/googledrive.ts")); +const dropbox_1 = __importDefault(__webpack_require__(/*! ./dropbox */ "./src/dropbox.ts")); +const discover_1 = __importDefault(__webpack_require__(/*! ./discover */ "./src/discover.ts")); +const sync_error_1 = __importDefault(__webpack_require__(/*! ./sync-error */ "./src/sync-error.ts")); +const unauthorized_error_1 = __importDefault(__webpack_require__(/*! ./unauthorized-error */ "./src/unauthorized-error.ts")); +const features_1 = __importDefault(__webpack_require__(/*! ./features */ "./src/features.ts")); +// TODO this is assigned to RemoteStorage.util later; check if still needed +const util = __importStar(__webpack_require__(/*! ./util */ "./src/util.ts")); +const globalContext = (0, util_1.getGlobalContext)(); +// declare global { +// interface Window { cordova: any }; +// } +let hasLocalStorage; +// TODO document and/or refactor (seems weird) +function emitUnauthorized(r) { + if (r.statusCode === 403 || r.statusCode === 401) { + this._emit('error', new unauthorized_error_1.default()); + } + return Promise.resolve(r); +} +/** +* Check if interval is valid: numeric and between 2s and 1hr inclusive +*/ +function isValidInterval(interval) { + return (typeof interval === 'number' && + interval >= 2000 && + interval <= 3600000); +} +/** + * Constructor for the remoteStorage object/instance + * + * This class primarily contains feature detection code and convenience API. + * + * Depending on which features are built in, it contains different attributes + * and functions. See the individual features for more information. + * + * @param {object} config - an optional configuration object + * @class + */ +class RemoteStorage { + constructor(cfg) { + /** + * Pending get/put/delete calls + * @private + */ + this._pending = []; + /** + * TODO: document + */ + this._cleanups = []; + /** + * TODO: document + */ + this._pathHandlers = { change: {} }; + /** + * Holds OAuth app keys for Dropbox, Google Drive + */ + this.apiKeys = {}; + // + // FEATURES INITIALIZATION + // + this._init = features_1.default.loadFeatures; + this.features = features_1.default.features; + this.loadFeature = features_1.default.loadFeature; + this.featureSupported = features_1.default.featureSupported; + this.featureDone = features_1.default.featureDone; + this.featuresDone = features_1.default.featuresDone; + this.featuresLoaded = features_1.default.featuresLoaded; + this.featureInitialized = features_1.default.featureInitialized; + this.featureFailed = features_1.default.featureFailed; + this.hasFeature = features_1.default.hasFeature; + this._setCachingModule = features_1.default._setCachingModule; + this._collectCleanupFunctions = features_1.default._collectCleanupFunctions; + this._fireReady = features_1.default._fireReady; + this.initFeature = features_1.default.initFeature; + // Initial configuration property settings. + // TODO use modern JS to merge object properties + if (typeof cfg === 'object') { + (0, util_1.extend)(config_1.default, cfg); + } + this.addEvents([ + 'ready', 'authing', 'connecting', 'connected', 'disconnected', + 'not-connected', 'conflict', 'error', 'features-loaded', + 'sync-interval-change', 'sync-req-done', 'sync-done', + 'wire-busy', 'wire-done', 'network-offline', 'network-online' + ]); + this._setGPD({ + get: this._pendingGPD('get'), + put: this._pendingGPD('put'), + delete: this._pendingGPD('delete') + }); + hasLocalStorage = (0, util_1.localStorageAvailable)(); + if (hasLocalStorage) { + this.apiKeys = (0, util_1.getJSONFromLocalStorage)('remotestorage:api-keys') || {}; + this.setBackend(localStorage.getItem('remotestorage:backend') || 'remotestorage'); + } + // Keep a reference to the orginal `on` function + const origOn = this.on; + /** + * Register an event handler. See :ref:`rs-events` for available event names. + * + * @param {string} eventName - Name of the event + * @param {function} handler - Event handler + */ + this.on = function (eventName, handler) { + if (this._allLoaded) { + // check if the handler should be called immediately, because the + // event has happened already + switch (eventName) { + case 'features-loaded': + setTimeout(handler, 0); + break; + case 'ready': + if (this.remote) { + setTimeout(handler, 0); + } + break; + case 'connected': + if (this.remote && this.remote.connected) { + setTimeout(handler, 0); + } + break; + case 'not-connected': + if (this.remote && !this.remote.connected) { + setTimeout(handler, 0); + } + break; + } + } + return origOn.call(this, eventName, handler); + }; + // load all features and emit `ready` + this._init(); + /** + * TODO: document + */ + this.fireInitial = function () { + if (this.local) { + setTimeout(this.local.fireInitial.bind(this.local), 0); + } + }.bind(this); + this.on('ready', this.fireInitial.bind(this)); + this.loadModules(); + } + /** + * Indicating if remoteStorage is currently connected. + */ + get connected() { + return this.remote.connected; + } + /** + * Load all modules passed as arguments + * @private + */ + loadModules() { + config_1.default.modules.forEach(this.addModule.bind(this)); + } + /** + * Initiate the OAuth authorization flow. + * + * This function is called by custom storage backend implementations + * (e.g. Dropbox or Google Drive). + * + * @param {object} options + * @param {string} options.authURL - URL of the authorization endpoint + * @param {string} [options.scope] - access scope + * @param {string} [options.clientId] - client identifier (defaults to the + * origin of the redirectUri) + * @private + */ + authorize(options) { + this.access.setStorageType(this.remote.storageApi); + if (typeof options.scope === 'undefined') { + options.scope = this.access.scopeParameter; + } + if (globalContext.cordova) { + options.redirectUri = config_1.default.cordovaRedirectUri; + } + else { + const location = authorize_1.default.getLocation(); + let redirectUri = location.origin; + if (location.pathname !== '/') { + redirectUri += location.pathname; + } + options.redirectUri = redirectUri; + } + if (typeof options.clientId === 'undefined') { + options.clientId = options.redirectUri.match(/^(https?:\/\/[^/]+)/)[0]; + } + authorize_1.default.authorize(this, options); + } + /** + * TODO: document + * @private + */ + impliedauth(storageApi, redirectUri) { + // TODO shouldn't these be default argument values? + storageApi = storageApi || this.remote.storageApi; + redirectUri = redirectUri || String(document.location); + (0, log_1.default)('ImpliedAuth proceeding due to absent authURL; storageApi = ' + storageApi + ' redirectUri = ' + redirectUri); + // Set a fixed access token, signalling to not send it as Bearer + this.remote.configure({ + token: authorize_1.default.IMPLIED_FAKE_TOKEN + }); + document.location.href = redirectUri; + } + /** + * @property {object} remote + * + * Depending on the chosen backend, this is either an instance of ``WireClient``, + * ``Dropbox`` or ``GoogleDrive``. + * + * @property {boolean} remote.connected - Whether or not a remote store is connected + * @property {boolean} remote.online - Whether last sync action was successful or not + * @property {string} remote.userAddress - The user address of the connected user + * @property {string} remote.properties - The properties of the WebFinger link + */ + /** + * Connect to a remoteStorage server. + * + * Discovers the WebFinger profile of the given user address and initiates + * the OAuth dance. + * + * This method must be called *after* all required access has been claimed. + * When using the connect widget, it will call this method itself. + * + * Special cases: + * + * 1. If a bearer token is supplied as second argument, the OAuth dance + * will be skipped and the supplied token be used instead. This is + * useful outside of browser environments, where the token has been + * acquired in a different way. + * + * 2. If the Webfinger profile for the given user address doesn't contain + * an auth URL, the library will assume that client and server have + * established authorization among themselves, which will omit bearer + * tokens in all requests later on. This is useful for example when using + * Kerberos and similar protocols. + * + * @param {string} userAddress - The user address (user@host) or URL to connect to. + * @param {string} token - (optional) A bearer token acquired beforehand + */ + connect(userAddress, token) { + this.setBackend('remotestorage'); + if (userAddress.indexOf('@') < 0 && !userAddress.match(/^(https?:\/\/)?[^\s\/$\.?#]+\.[^\s]*$/)) { + this._emit('error', new RemoteStorage.DiscoveryError("Not a valid user address or URL.")); + return; + } + // Prefix URL with https:// if it's missing + if (userAddress.indexOf('@') < 0 && !userAddress.match(/^https?:\/\//)) { + userAddress = `https://${userAddress}`; + } + if (globalContext.cordova) { + if (typeof config_1.default.cordovaRedirectUri !== 'string') { + this._emit('error', new RemoteStorage.DiscoveryError("Please supply a custom HTTPS redirect URI for your Cordova app")); + return; + } + if (!globalContext.cordova.InAppBrowser) { + this._emit('error', new RemoteStorage.DiscoveryError("Please include the InAppBrowser Cordova plugin to enable OAuth")); + return; + } + } + this.remote.configure({ + userAddress: userAddress + }); + this._emit('connecting'); + const discoveryTimeout = setTimeout(() => { + this._emit('error', new RemoteStorage.DiscoveryError("No storage information found for this user address.")); + }, config_1.default.discoveryTimeout); + (0, discover_1.default)(userAddress).then((info) => { + clearTimeout(discoveryTimeout); + this._emit('authing'); + info.userAddress = userAddress; + this.remote.configure(info); + if (!this.remote.connected) { + if (info.authURL) { + if (typeof token === 'undefined') { + // Normal authorization step; the default way to connect + this.authorize({ authURL: info.authURL }); + } + else if (typeof token === 'string') { + // Token supplied directly by app/developer/user + (0, log_1.default)('Skipping authorization sequence and connecting with known token'); + this.remote.configure({ token: token }); + } + else { + throw new Error("Supplied bearer token must be a string"); + } + } + else { + // In lieu of an excplicit authURL, assume that the browser and + // server handle any authorization needs; for instance, TLS may + // trigger the browser to use a client certificate, or a 401 Not + // Authorized response may make the browser send a Kerberos ticket + // using the SPNEGO method. + this.impliedauth(); + } + } + }, ( /*err*/) => { + clearTimeout(discoveryTimeout); + this._emit('error', new RemoteStorage.DiscoveryError("No storage information found for this user address.")); + }); + } + /** + * Reconnect the remote server to get a new authorization. + */ + reconnect() { + this.remote.configure({ token: null }); + if (this.backend === 'remotestorage') { + this.connect(this.remote.userAddress); + } + else { + this.remote.connect(); + } + } + /** + * "Disconnect" from remote server to terminate current session. + * + * This method clears all stored settings and deletes the entire local + * cache. + */ + disconnect() { + if (this.remote) { + this.remote.configure({ + userAddress: null, + href: null, + storageApi: null, + token: null, + properties: null + }); + } + this._setGPD({ + get: this._pendingGPD('get'), + put: this._pendingGPD('put'), + delete: this._pendingGPD('delete') + }); + const n = this._cleanups.length; + let i = 0; + const oneDone = () => { + i++; + if (i >= n) { + this._init(); + // FIXME Re-enable when modules are all imports + // log('Done cleaning up, emitting disconnected and disconnect events'); + this._emit('disconnected'); + } + }; + if (n > 0) { + this._cleanups.forEach((cleanup) => { + const cleanupResult = cleanup(this); + if (typeof (cleanupResult) === 'object' && typeof (cleanupResult.then) === 'function') { + cleanupResult.then(oneDone); + } + else { + oneDone(); + } + }); + } + else { + oneDone(); + } + } + /** + * TODO: document + * @private + */ + setBackend(what) { + this.backend = what; + if (hasLocalStorage) { + if (what) { + localStorage.setItem('remotestorage:backend', what); + } + else { + localStorage.removeItem('remotestorage:backend'); + } + } + } + /** + * Add a "change" event handler to the given path. Whenever a "change" + * happens (as determined by the backend, such as e.g. + * ) and the affected path is equal to or below the + * given 'path', the given handler is called. + * + * You should usually not use this method directly, but instead use the + * "change" events provided by :doc:`BaseClient ` + * + * @param {string} path - Absolute path to attach handler to + * @param {function} handler - Handler function + */ + onChange(path, handler) { + if (!this._pathHandlers.change[path]) { + this._pathHandlers.change[path] = []; + } + this._pathHandlers.change[path].push(handler); + } + /** + * TODO: do we still need this, now that we always instantiate the prototype? + * + * Enable remoteStorage logging. + */ + enableLog() { + config_1.default.logging = true; + } + /** + * TODO: do we still need this, now that we always instantiate the prototype? + * + * Disable remoteStorage logging + */ + disableLog() { + config_1.default.logging = false; + } + /** + * log + * + * The same as . + */ + log(...args) { + log_1.default.apply(RemoteStorage, args); + } + /** + * Set the OAuth key/ID for either GoogleDrive or Dropbox backend support. + * + * @param {Object} apiKeys - A config object with these properties: + * @param {string} [apiKeys.type] - Backend type: 'googledrive' or 'dropbox' + * @param {string} [apiKeys.key] - Client ID for GoogleDrive, or app key for Dropbox + */ + setApiKeys(apiKeys) { + const validTypes = [ApiKeyType.GOOGLE, ApiKeyType.DROPBOX]; + if (typeof apiKeys !== 'object' || !Object.keys(apiKeys).every(type => validTypes.includes(type))) { + console.error('setApiKeys() was called with invalid arguments'); + return false; + } + Object.keys(apiKeys).forEach(type => { + const key = apiKeys[type]; + if (!key) { + delete this.apiKeys[type]; + return; + } + switch (type) { + case ApiKeyType.DROPBOX: + this.apiKeys[ApiKeyType.DROPBOX] = { appKey: key }; + if (typeof this.dropbox === 'undefined' || + this.dropbox.clientId !== key) { + dropbox_1.default._rs_init(this); + } + break; + case ApiKeyType.GOOGLE: + this.apiKeys[ApiKeyType.GOOGLE] = { clientId: key }; + if (typeof this.googledrive === 'undefined' || + this.googledrive.clientId !== key) { + googledrive_1.default._rs_init(this); + } + break; + } + return true; + }); + if (hasLocalStorage) { + localStorage.setItem('remotestorage:api-keys', JSON.stringify(this.apiKeys)); + } + } + /** + * Set redirect URI to be used for the OAuth redirect within the + * in-app-browser window in Cordova apps. + * + * @param uri - A valid HTTP(S) URI + */ + setCordovaRedirectUri(uri) { + if (typeof uri !== 'string' || !uri.match(/http(s)?:\/\//)) { + throw new Error("Cordova redirect URI must be a URI string"); + } + config_1.default.cordovaRedirectUri = uri; + } + // + // GET/PUT/DELETE INTERFACE HELPERS + // + /** + * TODO: document + * @private + */ + _setGPD(impl, context) { + function wrap(func) { + return function (...args) { + return func.apply(context, args) + .then(emitUnauthorized.bind(this)); + }; + } + this.get = wrap(impl.get); + this.put = wrap(impl.put); + this.delete = wrap(impl.delete); + } + /** + * TODO: document + * @private + */ + _pendingGPD(methodName) { + return (...args) => { + const methodArguments = Array.prototype.slice.call(args); + return new Promise((resolve, reject) => { + this._pending.push({ + method: methodName, + args: methodArguments, + promise: { + resolve: resolve, + reject: reject + } + }); + }); + }; + } + /** + * TODO: document + * @private + */ + _processPending() { + this._pending.forEach((pending) => { + try { + this[pending.method](...pending.args).then(pending.promise.resolve, pending.promise.reject); + } + catch (e) { + pending.promise.reject(e); + } + }); + this._pending = []; + } + // + // CHANGE EVENT HANDLING + // + /** + * TODO: document + * @private + */ + _bindChange(object) { + object.on('change', this._dispatchEvent.bind(this, 'change')); + } + /** + * TODO: document + * @private + */ + _dispatchEvent(eventName, event) { + Object.keys(this._pathHandlers[eventName]).forEach((path) => { + const pl = path.length; + if (event.path.substr(0, pl) === path) { + this._pathHandlers[eventName][path].forEach((handler) => { + const ev = {}; + for (const key in event) { + ev[key] = event[key]; + } + ev.relativePath = event.path.replace(new RegExp('^' + path), ''); + try { + handler(ev); + } + catch (e) { + console.error("'change' handler failed: ", e, e.stack); + this._emit('error', e); + } + }); + } + }); + } + /** + * This method enables you to quickly instantiate a BaseClient, which you can + * use to directly read and manipulate data in the connected storage account. + * + * Please use this method only for debugging and development, and choose or + * create a :doc:`data module ` for your app to use. + * + * @param path - The base directory of the BaseClient that will be returned + * (with a leading and a trailing slash) + * + * @returns A client with the specified scope (category/base directory) + */ + scope(path) { + if (typeof (path) !== 'string') { + throw 'Argument \'path\' of baseClient.scope must be a string'; + } + if (!this.access.checkPathPermission(path, 'r')) { + console.warn('WARNING: Please use remoteStorage.access.claim() to ask for access permissions first: https://remotestoragejs.readthedocs.io/en/latest/js-api/access.html#claim'); + } + return new baseclient_1.default(this, path); + } + /** + * Get the value of the sync interval when application is in the foreground + * + * @returns {number} A number of milliseconds + */ + getSyncInterval() { + return config_1.default.syncInterval; + } + /** + * Set the value of the sync interval when application is in the foreground + * + * @param interval - Sync interval in milliseconds (between 2000 and 3600000 [1 hour]) + */ + setSyncInterval(interval) { + if (!isValidInterval(interval)) { + throw interval + " is not a valid sync interval"; + } + const oldValue = config_1.default.syncInterval; + config_1.default.syncInterval = interval; + this._emit('sync-interval-change', { oldValue: oldValue, newValue: interval }); + } + /** + * Get the value of the sync interval when application is in the background + * + * @returns A number of milliseconds + */ + getBackgroundSyncInterval() { + return config_1.default.backgroundSyncInterval; + } + /** + * Set the value of the sync interval when the application is in the + * background + * + * @param interval - Sync interval in milliseconds (between 2000 and 3600000 [1 hour]) + */ + setBackgroundSyncInterval(interval) { + if (!isValidInterval(interval)) { + throw interval + " is not a valid sync interval"; + } + const oldValue = config_1.default.backgroundSyncInterval; + config_1.default.backgroundSyncInterval = interval; + this._emit('sync-interval-change', { oldValue: oldValue, newValue: interval }); + } + /** + * Get the value of the current sync interval. Can be background or + * foreground, custom or default. + * + * @returns {number} A number of milliseconds + */ + getCurrentSyncInterval() { + return config_1.default.isBackground ? config_1.default.backgroundSyncInterval : config_1.default.syncInterval; + } + /** + * Get the value of the current network request timeout + * + * @returns {number} A number of milliseconds + */ + getRequestTimeout() { + return config_1.default.requestTimeout; + } + /** + * Set the timeout for network requests. + * + * @param timeout - Timeout in milliseconds + */ + setRequestTimeout(timeout) { + if (typeof timeout !== 'number') { + throw timeout + " is not a valid request timeout"; + } + config_1.default.requestTimeout = timeout; + } + /** + * TODO: document + * @private + */ + syncCycle() { + if (!this.sync || this.sync.stopped) { + return; + } + this.on('sync-done', () => { + // FIXME Re-enable when modules are all imports + // log('[Sync] Sync done. Setting timer to', this.getCurrentSyncInterval()); + if (this.sync && !this.sync.stopped) { + if (this._syncTimer) { + clearTimeout(this._syncTimer); + this._syncTimer = undefined; + } + this._syncTimer = setTimeout(this.sync.sync.bind(this.sync), this.getCurrentSyncInterval()); + } + }); + this.sync.sync(); + } + /** + * Start synchronization with remote storage, downloading and uploading any + * changes within the cached paths. + * + * Please consider: local changes will attempt sync immediately, and remote + * changes should also be synced timely when using library defaults. So + * this is mostly useful for letting users sync manually, when pressing a + * sync button for example. This might feel safer to them sometimes, esp. + * when shifting between offline and online a lot. + * + * @returns {Promise} A Promise which resolves when the sync has finished + */ + startSync() { + if (!config_1.default.cache) { + console.warn('Nothing to sync, because caching is disabled.'); + return Promise.resolve(); + } + this.sync.stopped = false; + this.syncStopped = false; + return this.sync.sync(); + } + /** + * Stop the periodic synchronization. + */ + stopSync() { + clearTimeout(this._syncTimer); + this._syncTimer = undefined; + if (this.sync) { + // FIXME Re-enable when modules are all imports + // log('[Sync] Stopping sync'); + this.sync.stopped = true; + } + else { + // The sync class has not been initialized yet, so we make sure it will + // not start the syncing process as soon as it's initialized. + // FIXME Re-enable when modules are all imports + // log('[Sync] Will instantiate sync stopped'); + this.syncStopped = true; + } + } + /* + * Add remoteStorage data module + * + * @param {Object} module - module object needs following properies: + * @param {string} [module.name] - Name of the module + * @param {function} [module.builder] - Builder function defining the module + * + * The module builder function should return an object containing another + * object called exports, which will be exported to this + * instance under the module's name. So when defining a locations module, + * like in the example below, it would be accessible via + * `remoteStorage.locations`, which would in turn have a `features` and a + * `collections` property. + * + * The function receives a private and a public client, which are both + * instances of . In the following example, the + * scope of privateClient is `/locations` and the scope of publicClient is + * `/public/locations`. + * + * @example + * RemoteStorage.addModule({name: 'locations', builder: function (privateClient, publicClient) { + * return { + * exports: { + * features: privateClient.scope('features/').defaultType('feature'), + * collections: privateClient.scope('collections/').defaultType('feature-collection') + * } + * }; + * }}); + */ + addModule(module) { + const moduleName = module.name; + const moduleBuilder = module.builder; + Object.defineProperty(this, moduleName, { + configurable: true, + get: function () { + const instance = this._loadModule(moduleName, moduleBuilder); + Object.defineProperty(this, moduleName, { + value: instance + }); + return instance; + } + }); + if (moduleName.indexOf('-') !== -1) { + const camelizedName = moduleName.replace(/\-[a-z]/g, function (s) { + return s[1].toUpperCase(); + }); + Object.defineProperty(this, camelizedName, { + get: function () { + return this[moduleName]; + } + }); + } + } + /** + * Load module + * @private + */ + _loadModule(moduleName, moduleBuilder) { + if (moduleBuilder) { + const module = moduleBuilder(new baseclient_1.default(this, '/' + moduleName + '/'), new baseclient_1.default(this, '/public/' + moduleName + '/')); + return module.exports; + } + else { + throw "Unknown module: " + moduleName; + } + } +} +// FIXME: Instead of doing this, would be better to only +// export setAuthURL / getAuthURL from RemoteStorage prototype +RemoteStorage.Authorize = authorize_1.default; +RemoteStorage.SyncError = sync_error_1.default; +RemoteStorage.Unauthorized = unauthorized_error_1.default; +RemoteStorage.DiscoveryError = discover_1.default.DiscoveryError; +RemoteStorage.util = util; +/** + * @property access + * + * Tracking claimed access scopes. A instance. +*/ +Object.defineProperty(RemoteStorage.prototype, 'access', { + get: function () { + const access = new access_1.default(); + Object.defineProperty(this, 'access', { + value: access + }); + return access; + }, + configurable: true +}); +// TODO Clean up/harmonize how modules are loaded and/or document this architecture properly +// +// At this point the remoteStorage object has not been created yet. +// Only its prototype exists so far, so we define a self-constructing +// property on there: +/** + * Property: caching + * + * Caching settings. A instance. + */ +// FIXME Was in rs_init of Caching but don't want to require RemoteStorage from there. +Object.defineProperty(RemoteStorage.prototype, 'caching', { + configurable: true, + get: function () { + const caching = new caching_1.default(); + Object.defineProperty(this, 'caching', { + value: caching + }); + return caching; + } +}); +(0, util_1.applyMixins)(RemoteStorage, [eventhandling_1.default]); +var ApiKeyType; +(function (ApiKeyType) { + ApiKeyType["GOOGLE"] = "googledrive"; + ApiKeyType["DROPBOX"] = "dropbox"; +})(ApiKeyType || (ApiKeyType = {})); +module.exports = RemoteStorage; + + +/***/ }), + +/***/ "./src/requests.ts": +/*!*************************!*\ + !*** ./src/requests.ts ***! + \*************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global) { +/** + * This file implements an HTTP request with timeout, on top of fetch or XHR. + * The returned value always looks like an XHR. + * It is used by authorize.ts, wireclient.ts, googledrive.ts and dropbox.ts. + * The timeout is set by RemoteStorage#setRequestTimeout(timeout) + */ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.requestWithTimeout = exports.isArrayBufferView = exports.retryAfterMs = void 0; +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const config_1 = __importDefault(__webpack_require__(/*! ./config */ "./src/config.ts")); +/** + * Extracts a retry interval from header, + * defaulting to three tries and a pause, within sync interval + * */ +function retryAfterMs(xhr) { + const serverMs = parseInt(xhr.getResponseHeader('Retry-After')) * 1000; + if (serverMs >= 1000) { // sanity check + return serverMs; + } + else { // value is NaN if no such header, or malformed + // three tries and a pause, within sync interval, + // with lower & upper bounds + return Math.max(1500, Math.min(60000, Math.round(config_1.default.syncInterval / (2.9 + Math.random() * 0.2)))); + } +} +exports.retryAfterMs = retryAfterMs; +if (typeof ((global || window).ArrayBufferView) === 'function') { + exports.isArrayBufferView = function (object) { + return object && (object instanceof (global || window).ArrayBufferView); + }; +} +else { + const arrayBufferViews = [ + Int8Array, Uint8Array, Int16Array, Uint16Array, + Int32Array, Uint32Array, Float32Array, Float64Array + ]; + exports.isArrayBufferView = function (object) { + for (let i = 0; i < 8; i++) { + if (object instanceof arrayBufferViews[i]) { + return true; + } + } + return false; + }; +} +function requestWithTimeout(method, url, options) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof fetch === 'function') { + return _fetchRequestWithTimeout(method, url, options); + } + else if (typeof XMLHttpRequest === 'function') { + return _xhrRequestWithTimeout(method, url, options); + } + else { + return Promise.reject('[Requests] You need to add a polyfill for fetch or XMLHttpRequest'); + } + }); +} +exports.requestWithTimeout = requestWithTimeout; +function _fetchRequestWithTimeout(method, url, options) { + return __awaiter(this, void 0, void 0, function* () { + const abortController = typeof AbortController === 'function' ? + new AbortController() : + null; + let timeoutId; + const timeoutPromise = new Promise((_resolve, reject) => { + timeoutId = setTimeout(() => { + if (abortController) { + abortController.abort(); + } + reject('timeout'); + }, config_1.default.requestTimeout); + }); + let syntheticXhr; + const responseHeaders = {}; + const networkPromise = fetch(url, { + method: method, + headers: options.headers, + body: options.body, + signal: abortController ? abortController.signal : undefined + }).then((response) => { + (0, log_1.default)('[requests fetch]', response); + response.headers.forEach((value, headerName) => { + responseHeaders[headerName.toUpperCase()] = value; + }); + syntheticXhr = { + readyState: 4, + status: response.status, + statusText: response.statusText, + response: undefined, + getResponseHeader: (headerName) => { + return responseHeaders[headerName.toUpperCase()] || null; + }, + // responseText: 'foo', + responseType: options.responseType, + responseURL: url, + }; + switch (options.responseType) { + case 'arraybuffer': + return response.arrayBuffer(); + case 'blob': + return response.blob(); + case 'json': + return response.json(); + case undefined: + case '': + case 'text': + return response.text(); + default: // document + throw new Error("responseType 'document' is not currently supported using fetch"); + } + }).then((processedBody) => { + syntheticXhr.response = processedBody; + if (!options.responseType || options.responseType === 'text') { + syntheticXhr.responseText = processedBody; + } + return syntheticXhr; + }).finally(() => { + clearTimeout(timeoutId); + }); + return Promise.race([networkPromise, timeoutPromise]); + }); +} +function _xhrRequestWithTimeout(method, url, options) { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + (0, log_1.default)('[requests XHR]', method, url); + let timedOut = false; + const timer = setTimeout(() => { + timedOut = true; + reject('timeout'); + }, config_1.default.requestTimeout); + const xhr = new XMLHttpRequest(); + xhr.open(method, url, true); + if (options.responseType) { + xhr.responseType = options.responseType; + } + if (options.headers) { + for (const key in options.headers) { + xhr.setRequestHeader(key, options.headers[key]); + } + } + xhr.onload = () => { + if (timedOut) { + return; + } + clearTimeout(timer); + resolve(xhr); + }; + xhr.onerror = (error) => { + if (timedOut) { + return; + } + clearTimeout(timer); + reject(error); + }; + let body = options.body; + if (typeof (body) === 'object' && !(0, exports.isArrayBufferView)(body) && body instanceof ArrayBuffer) { + body = new Uint8Array(body); + } + xhr.send(body); + }); + }); +} + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../node_modules/webpack/buildin/global.js */ "./node_modules/webpack/buildin/global.js"))) + +/***/ }), + +/***/ "./src/revisioncache.ts": +/*!******************************!*\ + !*** ./src/revisioncache.ts ***! + \******************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/** + * A cache which can propagate changes up to parent folders and generate new + * revision ids for them. The generated revision id is consistent across + * different sessions. The keys for the cache are case-insensitive. + * + * @param defaultValue {string} the value that is returned for all keys that + * don't exist in the cache + * @class + */ +class RevisionCache { + constructor(defaultValue) { + this._itemsRev = {}; + this._storage = {}; + this._canPropagate = false; + this.defaultValue = defaultValue; + this.activatePropagation(); + } + /** + * Get a value from the cache or defaultValue, if the key is not in the + * cache + */ + get(key) { + key = key.toLowerCase(); + let stored = this._storage[key]; + if (typeof stored === 'undefined') { + stored = this.defaultValue; + this._storage[key] = stored; + } + return stored; + } + /** + * Set a value + */ + set(key, value) { + key = key.toLowerCase(); + if (this._storage[key] === value) { + return value; + } + this._storage[key] = value; + if (!value) { + delete this._itemsRev[key]; + } + this._updateParentFolderItemRev(key, value); + if (this._canPropagate) { + this._propagate(key); + } + return value; + } + /** + * Delete a value + */ + delete(key) { + return this.set(key, null); + } + /** + * Disables automatic update of folder revisions when a key value is updated + */ + deactivatePropagation() { + this._canPropagate = false; + return true; + } + /** + * Enables automatic update of folder revisions when a key value is updated + * and refreshes the folder revision ids for entire tree. + */ + activatePropagation() { + if (this._canPropagate) { + return true; + } + this._generateFolderRev("/"); + this._canPropagate = true; + return true; + } + /** + * Returns a hash code for a string. + */ + _hashCode(str) { + let hash = 0; + if (str.length === 0) { + return hash; + } + for (let i = 0; i < str.length; i++) { + const chr = str.charCodeAt(i); + // eslint-disable-next-line no-bitwise + hash = ((hash << 5) - hash) + chr; + // eslint-disable-next-line no-bitwise + hash |= 0; // Convert to 32bit integer + } + return hash; + } + /** + * Takes an array of strings and returns a hash of the items + */ + _generateHash(items) { + // We sort the items before joining them to ensure correct hash generation + // every time + const files = items.sort().join('|'); + const hash = "" + this._hashCode(files); + return hash; + } + /** + * Update the revision of a key in it's parent folder data + */ + _updateParentFolderItemRev(key, rev) { + if (key !== '/') { + const parentFolder = this._getParentFolder(key); + if (!this._itemsRev[parentFolder]) { + this._itemsRev[parentFolder] = {}; + } + const parentFolderItemsRev = this._itemsRev[parentFolder]; + if (!rev) { + delete parentFolderItemsRev[key]; + } + else { + parentFolderItemsRev[key] = rev; + } + //reset revision until root + this._updateParentFolderItemRev(parentFolder, this.defaultValue); + } + } + _getParentFolder(key) { + return key.substr(0, key.lastIndexOf('/', key.length - 2) + 1); + } + /** + * Propagate the changes to the parent folders and generate new revision ids + * for them + */ + _propagate(key) { + if (key !== '/') { + const parentFolder = this._getParentFolder(key); + const parentFolderItemsRev = this._itemsRev[parentFolder]; + const hashItems = []; + for (const path in parentFolderItemsRev) { + hashItems.push(parentFolderItemsRev[path]); + } + const newRev = this._generateHash(hashItems); + this.set(parentFolder, newRev); + } + } + /** + * Generate revision id for a folder and it's subfolders, by hashing it's + * listing + */ + _generateFolderRev(folder) { + const itemsRev = this._itemsRev[folder]; + let hash = this.defaultValue; + if (itemsRev) { + const hashItems = []; + for (const path in itemsRev) { + const isDir = (path.substr(-1) === '/'); + let hashItem; + if (isDir) { + hashItem = this._generateFolderRev(path); + } + else { + hashItem = itemsRev[path]; + } + hashItems.push(hashItem); + } + if (hashItems.length > 0) { + hash = this._generateHash(hashItems); + } + } + this.set(folder, hash); + return hash; + } +} +module.exports = RevisionCache; + + +/***/ }), + +/***/ "./src/schema-not-found-error.ts": +/*!***************************************!*\ + !*** ./src/schema-not-found-error.ts ***! + \***************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +class SchemaNotFound extends Error { + constructor(uri) { + super(); + const error = new Error("Schema not found: " + uri); + error.name = "SchemaNotFound"; + return error; + } +} +module.exports = SchemaNotFound; + + +/***/ }), + +/***/ "./src/sync-error.ts": +/*!***************************!*\ + !*** ./src/sync-error.ts ***! + \***************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +class SyncError extends Error { + constructor(originalError) { + super(); + this.name = 'SyncError'; + this.message = 'Sync failed: '; + if (typeof originalError === 'string') { + this.message += originalError; + } + else { + this.message += originalError.message; + this.stack = originalError.stack; + this.originalError = originalError; + } + } +} +module.exports = SyncError; + + +/***/ }), + +/***/ "./src/sync.ts": +/*!*********************!*\ + !*** ./src/sync.ts ***! + \*********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const config_1 = __importDefault(__webpack_require__(/*! ./config */ "./src/config.ts")); +const env_1 = __importDefault(__webpack_require__(/*! ./env */ "./src/env.ts")); +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const authorize_1 = __importDefault(__webpack_require__(/*! ./authorize */ "./src/authorize.ts")); +const sync_error_1 = __importDefault(__webpack_require__(/*! ./sync-error */ "./src/sync-error.ts")); +const unauthorized_error_1 = __importDefault(__webpack_require__(/*! ./unauthorized-error */ "./src/unauthorized-error.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +let syncCycleCb, syncOnConnect; +function taskFor(action, path, promise) { + return { action, path, promise }; +} +function nodeChanged(node, etag) { + return node.common.revision !== etag && + (!node.remote || node.remote.revision !== etag); +} +function isStaleChild(node) { + return node.remote && node.remote.revision && !node.remote.itemsMap && !node.remote.body; +} +function hasCommonRevision(node) { + return node.common && node.common.revision; +} +function hasNoRemoteChanges(node) { + if (node.remote && node.remote.revision && + node.remote.revision !== node.common.revision) { + return false; + } + return (node.common.body === undefined && node.remote.body === false) || + (node.remote.body === node.common.body && + node.remote.contentType === node.common.contentType); +} +function mergeMutualDeletion(node) { + if (node.remote && node.remote.body === false && + node.local && node.local.body === false) { + delete node.local; + } + return node; +} +function handleVisibility(env, rs) { + function handleChange(isForeground) { + const oldValue = rs.getCurrentSyncInterval(); + config_1.default.isBackground = !isForeground; + const newValue = rs.getCurrentSyncInterval(); + rs._emit('sync-interval-change', { oldValue: oldValue, newValue: newValue }); + } + env.on('background', () => handleChange(false)); + env.on('foreground', () => handleChange(true)); +} +/** + * Class: RemoteStorage.Sync + * + * This class basically does six things: + * + * - retrieve the remote version of relevant documents and folders + * - add all local and remote documents together into one tree + * - push local documents out if they don't exist remotely + * - push local changes out to remote documents (conditionally, to avoid race + * conditions where both have changed) + * - adopt the local version of a document to its remote version if both exist + * and they differ + * - delete the local version of a document if it was deleted remotely + * - if any GET requests were waiting for remote data, resolve them once this + * data comes in. + * + * It does this using requests to documents and folders. Whenever a folder GET + * comes in, it gives information about all the documents it contains (this is + * the `markChildren` function). + **/ +class Sync { + constructor(remoteStorage) { + this._finishedTasks = []; + this.rs = remoteStorage; + this._tasks = {}; + this._running = {}; + this._timeStarted = {}; + this.numThreads = 10; + this.rs.local.onDiff(path => { + this.addTask(path); + this.doTasks(); + }); + this.rs.caching.onActivate((path) => { + this.addTask(path); + this.doTasks(); + }); + this.addEvents(['done', 'req-done']); + } + now() { + return new Date().getTime(); + } + queueGetRequest(path) { + return new Promise((resolve, reject) => { + if (!this.rs.remote.connected) { + reject('cannot fulfill maxAge requirement - remote is not connected'); + } + else if (!this.rs.remote.online) { + reject('cannot fulfill maxAge requirement - remote is not online'); + } + else { + this.addTask(path, function () { + this.rs.local.get(path).then(r => resolve(r)); + }.bind(this)); + this.doTasks(); + } + }); + } + // FIXME force02 sounds like rs spec 02, thus could be removed + corruptServerItemsMap(itemsMap, force02) { + if ((typeof (itemsMap) !== 'object') || (Array.isArray(itemsMap))) { + return true; + } + for (const itemName in itemsMap) { + const item = itemsMap[itemName]; + if (typeof (item) !== 'object') { + return true; + } + if (typeof (item.ETag) !== 'string') { + return true; + } + if ((0, util_1.isFolder)(itemName)) { + if (itemName.substring(0, itemName.length - 1).indexOf('/') !== -1) { + return true; + } + } + else { + if (itemName.indexOf('/') !== -1) { + return true; + } + if (force02) { + if (typeof (item['Content-Type']) !== 'string') { + return true; + } + if (typeof (item['Content-Length']) !== 'number') { + return true; + } + } + } + } + return false; + } + corruptItemsMap(itemsMap) { + if ((typeof (itemsMap) !== 'object') || (Array.isArray(itemsMap))) { + return true; + } + for (const path in itemsMap) { + if (typeof itemsMap[path] !== 'boolean') { + return true; + } + } + return false; + } + corruptRevision(rev) { + return ((typeof (rev) !== 'object') || + (Array.isArray(rev)) || + (rev.revision && typeof (rev.revision) !== 'string') || + (rev.body && typeof (rev.body) !== 'string' && typeof (rev.body) !== 'object') || + (rev.contentType && typeof (rev.contentType) !== 'string') || + (rev.contentLength && typeof (rev.contentLength) !== 'number') || + (rev.timestamp && typeof (rev.timestamp) !== 'number') || + (rev.itemsMap && this.corruptItemsMap(rev.itemsMap))); + } + isCorrupt(node) { + return ((typeof (node) !== 'object') || + (Array.isArray(node)) || + (typeof (node.path) !== 'string') || + (this.corruptRevision(node.common)) || + (node.local && this.corruptRevision(node.local)) || + (node.remote && this.corruptRevision(node.remote)) || + (node.push && this.corruptRevision(node.push))); + } + hasTasks() { + return Object.getOwnPropertyNames(this._tasks).length > 0; + } + collectDiffTasks() { + return __awaiter(this, void 0, void 0, function* () { + let num = 0; + return this.rs.local.forAllNodes((node) => { + if (num > 100) { + return; + } + if (this.isCorrupt(node)) { + (0, log_1.default)('[Sync] WARNING: corrupt node in local cache', node); + if (typeof (node) === 'object' && node.path) { + this.addTask(node.path); + num++; + } + } + else if (this.needsFetch(node) && this.rs.access.checkPathPermission(node.path, 'r')) { + this.addTask(node.path); + num++; + } + else if ((0, util_1.isDocument)(node.path) && this.needsPush(node) && + this.rs.access.checkPathPermission(node.path, 'rw')) { + this.addTask(node.path); + num++; + } + }) + .then(() => num) + .catch(e => { throw e; }); + }); + } + inConflict(node) { + return (node.local && node.remote && + (node.remote.body !== undefined || node.remote.itemsMap)); + } + needsRefresh(node) { + if (node.common) { + if (!node.common.timestamp) { + return true; + } + return (this.now() - node.common.timestamp > config_1.default.syncInterval); + } + return false; + } + needsFetch(node) { + if (this.inConflict(node)) { + return true; + } + if (node.common && + node.common.itemsMap === undefined && + node.common.body === undefined) { + return true; + } + if (node.remote && + node.remote.itemsMap === undefined && + node.remote.body === undefined) { + return true; + } + return false; + } + needsPush(node) { + if (this.inConflict(node)) { + return false; + } + if (node.local && !node.push) { + return true; + } + } + needsRemotePut(node) { + return node.local && node.local.body; + } + needsRemoteDelete(node) { + return node.local && node.local.body === false; + } + getParentPath(path) { + const parts = path.match(/^(.*\/)([^\/]+\/?)$/); + if (parts) { + return parts[1]; + } + else { + throw new Error('Not a valid path: "' + path + '"'); + } + } + deleteChildPathsFromTasks() { + for (const path in this._tasks) { + const paths = (0, util_1.pathsFromRoot)(path); + for (let i = 1; i < paths.length; i++) { + if (this._tasks[paths[i]]) { + // move pending promises to parent task + if (Array.isArray(this._tasks[path]) && this._tasks[path].length) { + Array.prototype.push.apply(this._tasks[paths[i]], this._tasks[path]); + } + delete this._tasks[path]; + } + } + } + } + collectRefreshTasks() { + return __awaiter(this, void 0, void 0, function* () { + return this.rs.local.forAllNodes((node) => { + let parentPath; + if (this.needsRefresh(node)) { + try { + parentPath = this.getParentPath(node.path); + } + catch (e) { + // node.path is already '/', can't take parentPath + } + if (parentPath && this.rs.access.checkPathPermission(parentPath, 'r')) { + this.addTask(parentPath); + } + else if (this.rs.access.checkPathPermission(node.path, 'r')) { + this.addTask(node.path); + } + } + }) + .then(() => this.deleteChildPathsFromTasks()) + .catch((e) => { throw e; }); + }); + } + flush(nodes) { + for (const path in nodes) { + // Strategy is 'FLUSH' and no local changes exist + if (this.rs.caching.checkPath(path) === 'FLUSH' && + nodes[path] && !nodes[path].local) { + (0, log_1.default)('[Sync] Flushing', path); + nodes[path] = undefined; // Cause node to be flushed from cache + } + } + return nodes; + } + doTask(path) { + return this.rs.local.getNodes([path]).then((nodes) => { + const node = nodes[path]; + // First fetch: + if (typeof (node) === 'undefined') { + return taskFor('get', path, this.rs.remote.get(path)); + } + // Fetch known-stale child: + else if (isStaleChild(node)) { + return taskFor('get', path, this.rs.remote.get(path)); + } + // Push PUT: + else if (this.needsRemotePut(node)) { + node.push = (0, util_1.deepClone)(node.local); + node.push.timestamp = this.now(); + return this.rs.local.setNodes(this.flush(nodes)).then(() => { + let options; + if (hasCommonRevision(node)) { + options = { ifMatch: node.common.revision }; + } + else { + // Initial PUT (fail if something is already there) + options = { ifNoneMatch: '*' }; + } + return taskFor('put', path, this.rs.remote.put(path, node.push.body, node.push.contentType, options)); + }); + } + // Push DELETE: + else if (this.needsRemoteDelete(node)) { + node.push = { body: false, timestamp: this.now() }; + return this.rs.local.setNodes(this.flush(nodes)).then(() => { + if (hasCommonRevision(node)) { + return taskFor('delete', path, this.rs.remote.delete(path, { ifMatch: node.common.revision })); + } + else { // Ascertain current common or remote revision first + return taskFor('get', path, this.rs.remote.get(path)); + } + }); + } + // Conditional refresh: + else if (hasCommonRevision(node)) { + return taskFor('get', path, this.rs.remote.get(path, { ifNoneMatch: node.common.revision })); + } + else { + return taskFor('get', path, this.rs.remote.get(path)); + } + }); + } + autoMergeFolder(node) { + if (node.remote.itemsMap) { + node.common = node.remote; + delete node.remote; + if (node.common.itemsMap) { + for (const itemName in node.common.itemsMap) { + if (!node.local.itemsMap[itemName]) { + // Indicates the node is either newly being fetched + // has been deleted locally (whether or not leading to conflict); + // before listing it in local listings, check if a local deletion + // exists. + node.local.itemsMap[itemName] = false; + } + } + if ((0, util_1.equal)(node.local.itemsMap, node.common.itemsMap)) { + delete node.local; + } + } + } + return node; + } + autoMergeDocument(node) { + if (hasNoRemoteChanges(node)) { + node = mergeMutualDeletion(node); + delete node.remote; + } + else if (node.remote.body !== undefined) { + // keep/revert: + (0, log_1.default)('[Sync] Emitting keep/revert'); + this.rs.local._emitChange({ + origin: 'conflict', + path: node.path, + oldValue: node.local.body, + newValue: node.remote.body, + lastCommonValue: node.common.body, + oldContentType: node.local.contentType, + newContentType: node.remote.contentType, + lastCommonContentType: node.common.contentType + }); + if (node.remote.body) { + node.common = node.remote; + } + else { + node.common = {}; + } + delete node.remote; + delete node.local; + } + return node; + } + autoMerge(node) { + if (node.remote) { + if (node.local) { + if ((0, util_1.isFolder)(node.path)) { + return this.autoMergeFolder(node); + } + else { + return this.autoMergeDocument(node); + } + } + else { // no local changes + if ((0, util_1.isFolder)(node.path)) { + if (node.remote.itemsMap !== undefined) { + node.common = node.remote; + delete node.remote; + } + } + else { + if (node.remote.body !== undefined) { + const change = { + origin: 'remote', + path: node.path, + oldValue: (node.common.body === false ? undefined : node.common.body), + newValue: (node.remote.body === false ? undefined : node.remote.body), + oldContentType: node.common.contentType, + newContentType: node.remote.contentType + }; + if (change.oldValue || change.newValue) { + this.rs.local._emitChange(change); + } + if (!node.remote.body) { // no remote, so delete/don't create + return; + } + node.common = node.remote; + delete node.remote; + } + } + } + } + else { + if (node.common.body) { + this.rs.local._emitChange({ + origin: 'remote', + path: node.path, + oldValue: node.common.body, + newValue: undefined, + oldContentType: node.common.contentType, + newContentType: undefined + }); + } + return undefined; + } + return node; + } + updateCommonTimestamp(path, revision) { + return __awaiter(this, void 0, void 0, function* () { + return this.rs.local.getNodes([path]).then((nodes) => { + if (nodes[path] && + nodes[path].common && + nodes[path].common.revision === revision) { + nodes[path].common.timestamp = this.now(); + } + return this.rs.local.setNodes(this.flush(nodes)); + }); + }); + } + markChildren(path, itemsMap, changedNodes, missingChildren) { + return __awaiter(this, void 0, void 0, function* () { + const paths = []; + const meta = {}; + const recurse = {}; + for (const item in itemsMap) { + paths.push(path + item); + meta[path + item] = itemsMap[item]; + } + for (const childName in missingChildren) { + paths.push(path + childName); + } + return this.rs.local.getNodes(paths).then((nodes) => { + let cachingStrategy; + let node; + for (const nodePath in nodes) { + node = nodes[nodePath]; + if (meta[nodePath]) { + if (node && node.common) { + if (nodeChanged(node, meta[nodePath].ETag)) { + changedNodes[nodePath] = (0, util_1.deepClone)(node); + changedNodes[nodePath].remote = { + revision: meta[nodePath].ETag, + timestamp: this.now() + }; + changedNodes[nodePath] = this.autoMerge(changedNodes[nodePath]); + } + } + else { + cachingStrategy = this.rs.caching.checkPath(nodePath); + if (cachingStrategy === 'ALL') { + changedNodes[nodePath] = { + path: nodePath, + common: { + timestamp: this.now() + }, + remote: { + revision: meta[nodePath].ETag, + timestamp: this.now() + } + }; + } + } + if (changedNodes[nodePath] && meta[nodePath]['Content-Type']) { + changedNodes[nodePath].remote.contentType = meta[nodePath]['Content-Type']; + } + if (changedNodes[nodePath] && meta[nodePath]['Content-Length']) { + changedNodes[nodePath].remote.contentLength = meta[nodePath]['Content-Length']; + } + } + else if (missingChildren[nodePath.substring(path.length)] && node && node.common) { + if (node.common.itemsMap) { + for (const commonItem in node.common.itemsMap) { + recurse[nodePath + commonItem] = true; + } + } + if (node.local && node.local.itemsMap) { + for (const localItem in node.local.itemsMap) { + recurse[nodePath + localItem] = true; + } + } + if (node.remote || (0, util_1.isFolder)(nodePath)) { + changedNodes[nodePath] = undefined; + } + else { + changedNodes[nodePath] = this.autoMerge(node); + if (typeof changedNodes[nodePath] === 'undefined') { + const parentPath = this.getParentPath(nodePath); + const parentNode = changedNodes[parentPath]; + const itemName = nodePath.substring(path.length); + if (parentNode && parentNode.local) { + delete parentNode.local.itemsMap[itemName]; + if ((0, util_1.equal)(parentNode.local.itemsMap, parentNode.common.itemsMap)) { + delete parentNode.local; + } + } + } + } + } + } + return this.deleteRemoteTrees(Object.keys(recurse), changedNodes) + .then(changedObjs2 => { + return this.rs.local.setNodes(this.flush(changedObjs2)); + }); + }); + }); + } + deleteRemoteTrees(paths, changedNodes) { + return __awaiter(this, void 0, void 0, function* () { + if (paths.length === 0) { + return Promise.resolve(changedNodes); + } + return this.rs.local.getNodes(paths).then((nodes) => __awaiter(this, void 0, void 0, function* () { + const subPaths = {}; + function collectSubPaths(folder, path) { + if (folder && folder.itemsMap) { + for (const itemName in folder.itemsMap) { + subPaths[path + itemName] = true; + } + } + } + for (const path in nodes) { + const node = nodes[path]; + // TODO Why check for the node here? I don't think this check ever applies + if (!node) { + continue; + } + if ((0, util_1.isFolder)(path)) { + collectSubPaths(node.common, path); + collectSubPaths(node.local, path); + } + else { + if (node.common && typeof (node.common.body) !== undefined) { + changedNodes[path] = (0, util_1.deepClone)(node); + changedNodes[path].remote = { + body: false, + timestamp: this.now() + }; + changedNodes[path] = this.autoMerge(changedNodes[path]); + } + } + } + // Recurse whole tree depth levels at once: + return this.deleteRemoteTrees(Object.keys(subPaths), changedNodes) + .then(changedNodes2 => { + return this.rs.local.setNodes(this.flush(changedNodes2)); + }); + })); + }); + } + completeFetch(path, bodyOrItemsMap, contentType, revision) { + return __awaiter(this, void 0, void 0, function* () { + let paths; + let parentPath; + const pathsFromRootArr = (0, util_1.pathsFromRoot)(path); + if ((0, util_1.isFolder)(path)) { + paths = [path]; + } + else { + parentPath = pathsFromRootArr[1]; + paths = [path, parentPath]; + } + return this.rs.local.getNodes(paths).then((nodes) => { + let itemName; + let node = nodes[path]; + let parentNode; + const missingChildren = {}; + function collectMissingChildren(folder) { + if (folder && folder.itemsMap) { + for (itemName in folder.itemsMap) { + if (!bodyOrItemsMap[itemName]) { + missingChildren[itemName] = true; + } + } + } + } + if (typeof (node) !== 'object' || + node.path !== path || + typeof (node.common) !== 'object') { + node = { path: path, common: {} }; + nodes[path] = node; + } + node.remote = { + revision: revision, + timestamp: this.now() + }; + if ((0, util_1.isFolder)(path)) { + collectMissingChildren(node.common); + collectMissingChildren(node.remote); + node.remote.itemsMap = {}; + for (itemName in bodyOrItemsMap) { + node.remote.itemsMap[itemName] = true; + } + } + else { + node.remote.body = bodyOrItemsMap; + node.remote.contentType = contentType; + parentNode = nodes[parentPath]; + if (parentNode && parentNode.local && parentNode.local.itemsMap) { + itemName = path.substring(parentPath.length); + parentNode.local.itemsMap[itemName] = true; + if ((0, util_1.equal)(parentNode.local.itemsMap, parentNode.common.itemsMap)) { + delete parentNode.local; + } + } + } + nodes[path] = this.autoMerge(node); + return { + toBeSaved: nodes, + missingChildren: missingChildren + }; + }); + }); + } + completePush(path, action, conflict, revision) { + return __awaiter(this, void 0, void 0, function* () { + return this.rs.local.getNodes([path]).then((nodes) => { + const node = nodes[path]; + if (!node.push) { + this.stopped = true; + throw new Error('completePush called but no push version!'); + } + if (conflict) { + (0, log_1.default)('[Sync] We have a conflict'); + if (!node.remote || node.remote.revision !== revision) { + node.remote = { + revision: revision || 'conflict', + timestamp: this.now() + }; + delete node.push; + } + nodes[path] = this.autoMerge(node); + } + else { + node.common = { + revision: revision, + timestamp: this.now() + }; + if (action === 'put') { + node.common.body = node.push.body; + node.common.contentType = node.push.contentType; + if ((0, util_1.equal)(node.local.body, node.push.body) && + node.local.contentType === node.push.contentType) { + delete node.local; + } + delete node.push; + } + else if (action === 'delete') { + if (node.local.body === false) { // No new local changes since push; flush it. + nodes[path] = undefined; + } + else { + delete node.push; + } + } + } + return this.rs.local.setNodes(this.flush(nodes)); + }); + }); + } + dealWithFailure(path) { + return __awaiter(this, void 0, void 0, function* () { + return this.rs.local.getNodes([path]).then((nodes) => { + if (nodes[path]) { + delete nodes[path].push; + return this.rs.local.setNodes(this.flush(nodes)); + } + }); + }); + } + interpretStatus(statusCode) { + const status = { + statusCode: statusCode, + successful: undefined, + conflict: undefined, + unAuth: undefined, + notFound: undefined, + changed: undefined, + networkProblems: undefined + }; + if (typeof statusCode === 'string' && + (statusCode === 'offline' || statusCode === 'timeout')) { + status.successful = false; + status.networkProblems = true; + return status; + } + else if (typeof statusCode === 'number') { + const series = Math.floor(statusCode / 100); + status.successful = (series === 2 || + statusCode === 304 || + statusCode === 412 || + statusCode === 404), + status.conflict = (statusCode === 412); + status.unAuth = ((statusCode === 401 && this.rs.remote.token !== authorize_1.default.IMPLIED_FAKE_TOKEN) || + statusCode === 402 || + statusCode === 403); + status.notFound = (statusCode === 404); + status.changed = (statusCode !== 304); + return status; + } + } + handleGetResponse(path, status, bodyOrItemsMap, contentType, revision) { + return __awaiter(this, void 0, void 0, function* () { + if (status.notFound) { + if ((0, util_1.isFolder)(path)) { + bodyOrItemsMap = {}; + } + else { + bodyOrItemsMap = false; + } + } + if (status.changed) { + return this.completeFetch(path, bodyOrItemsMap, contentType, revision) + .then(dataFromFetch => { + if ((0, util_1.isFolder)(path)) { + if (this.corruptServerItemsMap(bodyOrItemsMap)) { + (0, log_1.default)('[Sync] WARNING: Discarding corrupt folder description from server for ' + path); + return false; + } + else { + return this.markChildren(path, bodyOrItemsMap, dataFromFetch.toBeSaved, dataFromFetch.missingChildren) + .then(() => { return true; }); + } + } + else { + return this.rs.local.setNodes(this.flush(dataFromFetch.toBeSaved)) + .then(() => { return true; }); + } + }); + } + else { + return this.updateCommonTimestamp(path, revision) + .then(() => { return true; }); + } + }); + } + handleResponse(path, action, r) { + const status = this.interpretStatus(r.statusCode); + if (status.successful) { + if (action === 'get') { + return this.handleGetResponse(path, status, r.body, r.contentType, r.revision); + } + else if (action === 'put' || action === 'delete') { + return this.completePush(path, action, status.conflict, r.revision).then(function () { + return true; + }); + } + else { + throw new Error(`cannot handle response for unknown action ${action}`); + } + } + else { + // Unsuccessful + let error; + if (status.unAuth) { + error = new unauthorized_error_1.default(); + } + else if (status.networkProblems) { + error = new sync_error_1.default('Network request failed.'); + } + else { + error = new Error('HTTP response code ' + status.statusCode + ' received.'); + } + return this.dealWithFailure(path).then(() => { + this.rs._emit('error', error); + throw error; + }); + } + } + finishTask(task, queueTask = true) { + if (task.action === undefined) { + delete this._running[task.path]; + return; + } + if (queueTask) { + (0, log_1.default)("[Sync] queue finished task:", task.path); + this._finishedTasks.push(task); + if (this._finishedTasks.length > 1) { + (0, log_1.default)("[Sync] delaying finished task:", task.path); + return; + } + } + (0, log_1.default)("[Sync] run task:", task.path); + return task.promise + .then(res => { + return this.handleResponse(task.path, task.action, res); + }, err => { + (0, log_1.default)('[Sync] wireclient rejects its promise!', task.path, task.action, err); + return this.handleResponse(task.path, task.action, { statusCode: 'offline' }); + }) + .then(completed => { + this._finishedTasks.shift(); + delete this._timeStarted[task.path]; + delete this._running[task.path]; + if (completed) { + if (this._tasks[task.path]) { + for (let i = 0; i < this._tasks[task.path].length; i++) { + this._tasks[task.path][i](); + } + delete this._tasks[task.path]; + } + } + this.rs._emit('sync-req-done'); + if (this._finishedTasks.length > 0) { + this.finishTask(this._finishedTasks[0], false); + return; + } + this.collectTasks(false).then(() => { + // See if there are any more tasks that are not refresh tasks + if (!this.hasTasks() || this.stopped) { + (0, log_1.default)('[Sync] Sync is done! Reschedule?', Object.getOwnPropertyNames(this._tasks).length, this.stopped); + if (!this.done) { + this.done = true; + this.rs._emit('sync-done'); + } + } + else { + // Use a 10ms timeout to let the JavaScript runtime catch its breath + // (and hopefully force an IndexedDB auto-commit?), and also to cause + // the threads to get staggered and get a good spread over time: + setTimeout(() => { this.doTasks(); }, 10); + } + }); + }, err => { + (0, log_1.default)('[Sync] Error', err); + this._finishedTasks.shift(); + delete this._timeStarted[task.path]; + delete this._running[task.path]; + this.rs._emit('sync-req-done'); + if (this._finishedTasks.length > 0) { + this.finishTask(this._finishedTasks[0], false); + return; + } + if (!this.done) { + this.done = true; + this.rs._emit('sync-done'); + } + }); + } + doTasks() { + let numToHave, numAdded = 0, path; + if (this.rs.remote.connected) { + if (this.rs.remote.online) { + numToHave = this.numThreads; + } + else { + numToHave = 1; + } + } + else { + numToHave = 0; + } + const numToAdd = numToHave - Object.getOwnPropertyNames(this._running).length; + if (numToAdd <= 0) { + return true; + } + for (path in this._tasks) { + if (!this._running[path]) { + this._timeStarted[path] = this.now(); + this._running[path] = this.doTask(path); + this._running[path].then(this.finishTask.bind(this)); + numAdded++; + if (numAdded >= numToAdd) { + return true; + } + } + } + return (numAdded >= numToAdd); + } + collectTasks(alsoCheckRefresh) { + return __awaiter(this, void 0, void 0, function* () { + if (this.hasTasks() || this.stopped) { + return Promise.resolve(); + } + return this.collectDiffTasks().then(numDiffs => { + if (numDiffs || alsoCheckRefresh === false) { + return Promise.resolve(); + } + else { + return this.collectRefreshTasks(); + } + }, function (err) { throw err; }); + }); + } + addTask(path, cb) { + if (!this._tasks[path]) { + this._tasks[path] = []; + } + if (typeof (cb) === 'function') { + this._tasks[path].push(cb); + } + } + /** + * Method: sync + **/ + sync() { + this.done = false; + if (!this.doTasks()) { + return this.collectTasks().then(() => { + try { + this.doTasks(); + } + catch (e) { + (0, log_1.default)('[Sync] doTasks error', e); + } + }, function (e) { + (0, log_1.default)('[Sync] Sync error', e); + throw new Error('Local cache unavailable'); + }); + } + else { + return Promise.resolve(); + } + } + static _rs_init(remoteStorage) { + syncCycleCb = function () { + // if (!config.cache) return false + (0, log_1.default)('[Sync] syncCycleCb calling syncCycle'); + const env = new env_1.default(); + if (env.isBrowser()) { + handleVisibility(env, remoteStorage); + } + if (!remoteStorage.sync) { + // Call this now that all other modules are also ready: + remoteStorage.sync = new Sync(remoteStorage); + if (remoteStorage.syncStopped) { + (0, log_1.default)('[Sync] Instantiating sync stopped'); + remoteStorage.sync.stopped = true; + delete remoteStorage.syncStopped; + } + } + (0, log_1.default)('[Sync] syncCycleCb calling syncCycle'); + remoteStorage.syncCycle(); + }; + syncOnConnect = function () { + remoteStorage.removeEventListener('connected', syncOnConnect); + remoteStorage.startSync(); + }; + remoteStorage.on('ready', syncCycleCb); + remoteStorage.on('connected', syncOnConnect); + } + static _rs_cleanup(remoteStorage) { + remoteStorage.stopSync(); + remoteStorage.removeEventListener('ready', syncCycleCb); + remoteStorage.removeEventListener('connected', syncOnConnect); + remoteStorage.sync = undefined; + delete remoteStorage.sync; + } +} +(0, util_1.applyMixins)(Sync, [eventhandling_1.default]); +module.exports = Sync; + + +/***/ }), + +/***/ "./src/syncedgetputdelete.ts": +/*!***********************************!*\ + !*** ./src/syncedgetputdelete.ts ***! + \***********************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +function shareFirst(path) { + return (this.backend === 'dropbox' && + !!path.match(/^\/public\/.*[^\/]$/)); +} +function defaultMaxAge(context) { + if ((typeof context.remote === 'object') && + context.remote.connected && context.remote.online) { + return 2 * context.getSyncInterval(); + } + else { + (0, log_1.default)('Not setting default maxAge, because remote is offline or not connected'); + return false; + } +} +const SyncedGetPutDelete = { + get: function (path, maxAge) { + if (!this.local) { + return this.remote.get(path); + } + else { + if (typeof maxAge === 'undefined') { + maxAge = defaultMaxAge(this); + } + else if (typeof maxAge !== 'number' && maxAge !== false) { + return Promise.reject(`Argument 'maxAge' must be 'false' or a number`); + } + return this.local.get(path, maxAge, this.sync.queueGetRequest.bind(this.sync)); + } + }, + put: function (path, body, contentType) { + if (shareFirst.bind(this)(path)) { + return SyncedGetPutDelete._wrapBusyDone.call(this, this.remote.put(path, body, contentType)); + } + else if (this.local) { + return this.local.put(path, body, contentType); + } + else { + return SyncedGetPutDelete._wrapBusyDone.call(this, this.remote.put(path, body, contentType)); + } + }, + 'delete': function (path) { + if (this.local) { + return this.local.delete(path); + } + else { + return SyncedGetPutDelete._wrapBusyDone.call(this, this.remote.delete(path)); + } + }, + _wrapBusyDone: function (result) { + return __awaiter(this, void 0, void 0, function* () { + this._emit('wire-busy'); + return result.then((r) => { + this._emit('wire-done', { success: true }); + return Promise.resolve(r); + }, (err) => { + this._emit('wire-done', { success: false }); + return Promise.reject(err); + }); + }); + } +}; +module.exports = SyncedGetPutDelete; + + +/***/ }), + +/***/ "./src/types.ts": +/*!**********************!*\ + !*** ./src/types.ts ***! + \**********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.BaseClientTypes = void 0; +/** + * - Manages and validates types of remoteStorage objects, using JSON-LD and + * JSON Schema + * - Adds schema declaration/validation methods to BaseClient instances. + **/ +class BaseClientTypes { + constructor() { + /** + * -> + */ + this.uris = {}; + /** + * Contains schema objects of all types known to the BaseClient instance + * + * -> + */ + this.schemas = {}; + /** + * -> + */ + this.aliases = {}; + } + /** + * Called via public function BaseClient.declareType() + * + * @private + */ + declare(moduleName, alias, uri, schema) { + const fullAlias = moduleName + '/' + alias; + if (schema.extends) { + const parts = schema.extends.split('/'); + const extendedAlias = (parts.length === 1) + ? moduleName + '/' + parts.shift() + : parts.join('/'); + const extendedUri = this.uris[extendedAlias]; + if (!extendedUri) { + throw "Type '" + fullAlias + "' tries to extend unknown schema '" + extendedAlias + "'"; + } + schema.extends = this.schemas[extendedUri]; + } + this.uris[fullAlias] = uri; + this.aliases[uri] = fullAlias; + this.schemas[uri] = schema; + } + resolveAlias(alias) { + return this.uris[alias]; + } + getSchema(uri) { + return this.schemas[uri]; + } + inScope(moduleName) { + const ml = moduleName.length; + const schemas = {}; + for (const alias in this.uris) { + if (alias.substr(0, ml + 1) === moduleName + '/') { + const uri = this.uris[alias]; + schemas[uri] = this.schemas[uri]; + } + } + return schemas; + } +} +exports.BaseClientTypes = BaseClientTypes; +const Types = new BaseClientTypes(); +exports.default = Types; + + +/***/ }), + +/***/ "./src/unauthorized-error.ts": +/*!***********************************!*\ + !*** ./src/unauthorized-error.ts ***! + \***********************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +class UnauthorizedError extends Error { + constructor(message, options = {}) { + super(); + this.name = 'Unauthorized'; + if (typeof message === 'undefined') { + this.message = 'App authorization expired or revoked.'; + } + else { + this.message = message; + } + if (typeof options.code !== 'undefined') { + this.code = options.code; + } + this.stack = (new Error()).stack; + } +} +module.exports = UnauthorizedError; + + +/***/ }), + +/***/ "./src/util.ts": +/*!*********************!*\ + !*** ./src/util.ts ***! + \*********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(global, Buffer) { +// Reusable utility functions +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.applyMixins = exports.generateCodeVerifier = exports.toBase64 = exports.getTextFromArrayBuffer = exports.shouldBeTreatedAsBinary = exports.getJSONFromLocalStorage = exports.localStorageAvailable = exports.pathsFromRoot = exports.deepClone = exports.equal = exports.bindAll = exports.cleanPath = exports.baseName = exports.isDocument = exports.isFolder = exports.containingFolder = exports.extend = exports.getGlobalContext = exports.globalContext = exports.logError = void 0; +/** + * Takes an object and its copy as produced by the _deepClone function + * below, and finds and fixes any ArrayBuffers that were cast to `{}` instead + * of being cloned to new ArrayBuffers with the same content. + * + * It recurses into sub-objects, but skips arrays if they occur. + */ +function _fixArrayBuffers(srcObj, dstObj) { + if (typeof (srcObj) !== 'object' || Array.isArray(srcObj) || srcObj === null) { + return; + } + for (const field in srcObj) { + if (typeof (srcObj[field]) === 'object' && srcObj[field] !== null) { + if (srcObj[field].toString() === '[object ArrayBuffer]') { + dstObj[field] = new ArrayBuffer(srcObj[field].byteLength); + const srcArr = new Int8Array(srcObj[field]); + const dstArr = new Int8Array(dstObj[field]); + dstArr.set(srcArr); + } + else { + _fixArrayBuffers(srcObj[field], dstObj[field]); + } + } + } +} +const logError = (error) => { + if (typeof (error) === 'string') { + console.error(error); + } + else { + console.error(error.message, error.stack); + } +}; +exports.logError = logError; +exports.globalContext = (typeof (window) !== 'undefined' ? window : (typeof self === 'object' ? self : global)); +const getGlobalContext = () => { + return (typeof (window) !== 'undefined' ? window : (typeof self === 'object' ? self : global)); +}; +exports.getGlobalContext = getGlobalContext; +// TODO Remove in favor of modern JS: +// `const mergedObject = { ...obj1, ..obj2 }` +const extend = (...args) => { + const target = args[0]; + const sources = Array.prototype.slice.call(args, 1); + sources.forEach(function (source) { + for (const key in source) { + target[key] = source[key]; + } + }); + return target; +}; +exports.extend = extend; +const containingFolder = (path) => { + if (path === '') { + return '/'; + } + if (!path) { + throw "Path not given!"; + } + return path.replace(/\/+/g, '/') + .replace(/[^\/]+\/?$/, ''); +}; +exports.containingFolder = containingFolder; +const isFolder = (path) => { + return path.slice(-1) === '/'; +}; +exports.isFolder = isFolder; +const isDocument = (path) => { + return !(0, exports.isFolder)(path); +}; +exports.isDocument = isDocument; +const baseName = (path) => { + const parts = path.split('/'); + if ((0, exports.isFolder)(path)) { + return parts[parts.length - 2] + '/'; + } + else { + return parts[parts.length - 1]; + } +}; +exports.baseName = baseName; +const cleanPath = (path) => { + return path.replace(/\/+/g, '/') + .split('/').map(encodeURIComponent).join('/') + .replace(/'/g, '%27'); +}; +exports.cleanPath = cleanPath; +const bindAll = (object) => { + for (const key in this) { + if (typeof (object[key]) === 'function') { + object[key] = object[key].bind(object); + } + } +}; +exports.bindAll = bindAll; +const equal = (a, b, seen = []) => { + let key; + if (typeof (a) !== typeof (b)) { + return false; + } + if (typeof (a) === 'number' || typeof (a) === 'boolean' || typeof (a) === 'string') { + return a === b; + } + if (typeof (a) === 'function') { + return a.toString() === b.toString(); + } + if (a instanceof ArrayBuffer && b instanceof ArrayBuffer) { + // Without the following conversion the browsers wouldn't be able to + // tell the ArrayBuffer instances apart. + a = new Uint8Array(a); + b = new Uint8Array(b); + } + // If this point has been reached, a and b are either arrays or objects. + if (a instanceof Array) { + if (a.length !== b.length) { + return false; + } + for (let i = 0, c = a.length; i < c; i++) { + if (!(0, exports.equal)(a[i], b[i], seen)) { + return false; + } + } + } + else { + // Check that keys from a exist in b + for (key in a) { + if (a.hasOwnProperty(key) && !(key in b)) { + return false; + } + } + // Check that keys from b exist in a, and compare the values + for (key in b) { + if (!b.hasOwnProperty(key)) { + continue; + } + if (!(key in a)) { + return false; + } + let seenArg; + if (typeof (b[key]) === 'object') { + if (seen.indexOf(b[key]) >= 0) { + // Circular reference, don't attempt to compare this object. + // If nothing else returns false, the objects match. + continue; + } + seenArg = seen.slice(); + seenArg.push(b[key]); + } + if (!(0, exports.equal)(a[key], b[key], seenArg)) { + return false; + } + } + } + return true; +}; +exports.equal = equal; +const deepClone = (obj) => { + if (obj === undefined) { + return undefined; + } + else { + const clone = JSON.parse(JSON.stringify(obj)); + _fixArrayBuffers(obj, clone); + return clone; + } +}; +exports.deepClone = deepClone; +const pathsFromRoot = (path) => { + const paths = [path]; + const parts = path.replace(/\/$/, '').split('/'); + while (parts.length > 1) { + parts.pop(); + paths.push(parts.join('/') + '/'); + } + return paths; +}; +exports.pathsFromRoot = pathsFromRoot; +const localStorageAvailable = () => { + const context = (0, exports.getGlobalContext)(); + if (!('localStorage' in context)) { + return false; + } + try { + context.localStorage.setItem('rs-check', '1'); + context.localStorage.removeItem('rs-check'); + return true; + } + catch (error) { + return false; + } +}; +exports.localStorageAvailable = localStorageAvailable; +/** + * Extract and parse JSON data from localStorage. + * + * @param {string} key - localStorage key + * + * @returns {object} parsed object or undefined + */ +const getJSONFromLocalStorage = (key) => { + const context = (0, exports.getGlobalContext)(); + try { + return JSON.parse(context.localStorage.getItem(key)); + } + catch (e) { + // no JSON stored + } +}; +exports.getJSONFromLocalStorage = getJSONFromLocalStorage; +/** + * Decide if data should be treated as binary based on the content (presence of non-printable characters + * or replacement character) and content-type. + * + * @param {string} content - The data + * @param {string} mimeType - The data's content-type + * + * @returns {boolean} + */ +const shouldBeTreatedAsBinary = (content, mimeType) => { + // eslint-disable-next-line no-control-regex + return !!((mimeType && mimeType.match(/charset=binary/)) || /[\x00-\x08\x0E-\x1F\uFFFD]/.test(content)); +}; +exports.shouldBeTreatedAsBinary = shouldBeTreatedAsBinary; +/** + * Read data from an ArrayBuffer and return it as a string + * @param {ArrayBuffer} arrayBuffer + * @param {string} encoding + * @returns {Promise} Resolves with a string containing the data + */ +const getTextFromArrayBuffer = (arrayBuffer, encoding) => { + return new Promise((resolve /*, reject*/) => { + if (typeof Blob === 'undefined') { + const buffer = Buffer.from(arrayBuffer); + resolve(buffer.toString(encoding)); + } + else { + let blob; + const gc = exports.globalContext; + // TODO fix as BlobBuilder is not available in all browsers + // @see https://developer.mozilla.org/en-US/docs/Web/API/BlobBuilder + gc.BlobBuilder = gc.BlobBuilder || gc.WebKitBlobBuilder; + if (typeof gc.BlobBuilder !== 'undefined') { + const bb = new gc.BlobBuilder(); + bb.append(arrayBuffer); + blob = bb.getBlob(); + } + else { + blob = new Blob([arrayBuffer]); + } + const fileReader = new FileReader(); + if (typeof fileReader.addEventListener === 'function') { + fileReader.addEventListener('loadend', function (evt) { + resolve(evt.target.result); + }); + } + else { + fileReader.onloadend = function (evt) { + resolve(evt.target.result); + }; + } + fileReader.readAsText(blob, encoding); + } + }); +}; +exports.getTextFromArrayBuffer = getTextFromArrayBuffer; +/** + * Encode string in base64 + * @param {String} str + * @returns {String} base64-encoded string + */ +const toBase64 = (str) => { + const context = (0, exports.getGlobalContext)(); + if ('btoa' in context) { + return context['btoa'](str); + } + else { + return Buffer.from(str).toString('base64'); + } +}; +exports.toBase64 = toBase64; +/** + * Generates values required for OAuth2 PKCE in a cryptographically secure manner. + * @param {number} [numChar=128] - length of codeVerifier to generate; from 43 to 128 + * + * @typedef {Object} PkceValues + * @property {string} codeVerifier - 43 to 128 chars from the 66-char set + * @property {string} codeChallenge - verifier hashed & base-64 URL encoded + * @property {string} state - a separate random value. Should be used to check redirect_uri. + * @returns PkceValues + */ +function generateCodeVerifier(numChar = 128) { + return __awaiter(this, void 0, void 0, function* () { + const randomBytes = new Uint8Array(numChar); + crypto.getRandomValues(randomBytes); + const charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'; + const randomChar = Array.from(randomBytes).map(byte => charSet[byte % charSet.length]); + const codeVerifier = randomChar.join(''); + const charsAsBytes = Uint8Array.from(randomChar.map(ch => ch.charCodeAt(0))); + const sha256hash = yield crypto.subtle.digest('SHA-256', charsAsBytes); + const codeChallenge = base64Urlencode(sha256hash); + crypto.getRandomValues(randomBytes); + const stateRandomChar = Array.from(randomBytes).map(byte => charSet[byte % charSet.length]); + const state = stateRandomChar.join(''); + return { codeVerifier, codeChallenge, state }; + }); +} +exports.generateCodeVerifier = generateCodeVerifier; +function base64Urlencode(str) { + return btoa(String.fromCharCode.apply(null, new Uint8Array(str))) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); +} +/* + * Apply mixins to an object + * + * https://www.typescriptlang.org/docs/handbook/mixins.html + * + * @param {object} Parent object + * @param {Array} Mixins to apply methods from + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function applyMixins(derivedCtor, baseCtors) { + baseCtors.forEach(baseCtor => { + Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { + Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name)); + }); + }); +} +exports.applyMixins = applyMixins; + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../node_modules/webpack/buildin/global.js */ "./node_modules/webpack/buildin/global.js"), __webpack_require__(/*! ./../node_modules/buffer/index.js */ "./node_modules/buffer/index.js").Buffer)) + +/***/ }), + +/***/ "./src/wireclient.ts": +/*!***************************!*\ + !*** ./src/wireclient.ts ***! + \***************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const authorize_1 = __importDefault(__webpack_require__(/*! ./authorize */ "./src/authorize.ts")); +const eventhandling_1 = __importDefault(__webpack_require__(/*! ./eventhandling */ "./src/eventhandling.ts")); +const unauthorized_error_1 = __importDefault(__webpack_require__(/*! ./unauthorized-error */ "./src/unauthorized-error.ts")); +const log_1 = __importDefault(__webpack_require__(/*! ./log */ "./src/log.ts")); +const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts"); +const requests_1 = __webpack_require__(/*! ./requests */ "./src/requests.ts"); +const remote_1 = __webpack_require__(/*! ./remote */ "./src/remote.ts"); +let hasLocalStorage; +const SETTINGS_KEY = 'remotestorage:wireclient'; +const API_2012 = 1; +const API_00 = 2; +const API_01 = 3; +const API_02 = 4; +const API_HEAD = 5; +const STORAGE_APIS = { + 'draft-dejong-remotestorage-00': API_00, + 'draft-dejong-remotestorage-01': API_01, + 'draft-dejong-remotestorage-02': API_02, + 'https://www.w3.org/community/rww/wiki/read-write-web-00#simple': API_2012 +}; +function readSettings() { + const settings = (0, util_1.getJSONFromLocalStorage)(SETTINGS_KEY) || {}; + const { userAddress, href, storageApi, token, properties } = settings; + return { userAddress, href, storageApi, token, properties }; +} +function determineCharset(mimeType) { + let charset = 'utf-8'; + let charsetMatch; + if (mimeType) { + charsetMatch = mimeType.match(/charset=(.+)$/); + if (charsetMatch) { + charset = charsetMatch[1]; + } + } + return charset; +} +function isFolderDescription(body) { + return ((body['@context'] === 'http://remotestorage.io/spec/folder-description') + && (typeof (body['items']) === 'object')); +} +function isSuccessStatus(status) { + return [201, 204, 304].indexOf(status) >= 0; +} +function isErrorStatus(status) { + return [401, 403, 404, 412].indexOf(status) >= 0; +} +class WireClient extends remote_1.RemoteBase { + constructor(rs) { + super(rs); + this._revisionCache = {}; + hasLocalStorage = (0, util_1.localStorageAvailable)(); + /** + * Event: connected + * Fired when the wireclient connect method realizes that it is in + * possession of a token and href + **/ + this.addEvents(['connected', 'not-connected']); + if (hasLocalStorage) { + const settings = readSettings(); + if (settings) { + setTimeout(() => { + this.configure(settings); + }, 0); + } + } + if (this.connected) { + setTimeout(this._emit.bind(this), 0, 'connected'); + } + } + get storageType() { + if (this.storageApi) { + const spec = this.storageApi.match(/draft-dejong-(remotestorage-\d\d)/); + return spec ? spec[1] : '2012.04'; + } + else { + return undefined; + } + } + _request(method, uri, token, headers, body, getEtag, fakeRevision) { + return __awaiter(this, void 0, void 0, function* () { + if (this.isForbiddenRequestMethod(method, uri)) { + return Promise.reject(`Don't use ${method} on directories!`); + } + let revision; + if (token !== authorize_1.default.IMPLIED_FAKE_TOKEN) { + headers['Authorization'] = 'Bearer ' + token; + } + this.rs._emit('wire-busy', { + method: method, + isFolder: (0, util_1.isFolder)(uri) + }); + return (0, requests_1.requestWithTimeout)(method, uri, { + body: body, + headers: headers, + responseType: 'arraybuffer' + }).then((response) => { + if (!this.online) { + this.online = true; + this.rs._emit('network-online'); + } + this.rs._emit('wire-done', { + method: method, + isFolder: (0, util_1.isFolder)(uri), + success: true + }); + if (isErrorStatus(response.status)) { + (0, log_1.default)('[WireClient] Error response status', response.status); + if (getEtag) { + revision = this.stripQuotes(response.getResponseHeader('ETag')); + } + else { + revision = undefined; + } + if (response.status === 401) { + this.rs._emit('error', new unauthorized_error_1.default()); + } + return Promise.resolve({ statusCode: response.status, revision: revision }); + } + else if (isSuccessStatus(response.status) || + (response.status === 200 && method !== 'GET')) { + revision = this.stripQuotes(response.getResponseHeader('ETag')); + (0, log_1.default)('[WireClient] Successful request', revision); + return Promise.resolve({ statusCode: response.status, revision: revision }); + } + else { + const mimeType = response.getResponseHeader('Content-Type'); + if (getEtag) { + revision = this.stripQuotes(response.getResponseHeader('ETag')); + } + else { + revision = (response.status === 200) ? fakeRevision : undefined; + } + const charset = determineCharset(mimeType); + if ((0, util_1.shouldBeTreatedAsBinary)(response.response, mimeType)) { + (0, log_1.default)('[WireClient] Successful request with unknown or binary mime-type', revision); + return Promise.resolve({ + statusCode: response.status, + body: response.response, + contentType: mimeType, + revision: revision + }); + } + else { + return (0, util_1.getTextFromArrayBuffer)(response.response, charset) + .then((textContent) => { + (0, log_1.default)('[WireClient] Successful request', revision); + return Promise.resolve({ + statusCode: response.status, + body: textContent, + contentType: mimeType, + revision: revision + }); + }); + } + } + }, error => { + if (this.online) { + this.online = false; + this.rs._emit('network-offline'); + } + this.rs._emit('wire-done', { + method: method, + isFolder: (0, util_1.isFolder)(uri), + success: false + }); + return Promise.reject(error); + }); + }); + } + /** + * Sets the userAddress, href, storageApi, token, and properties of a + * remote store. Also sets connected and online to true and emits the + * 'connected' event, if both token and href are present. + * + * Parameters: + * settings - An object that may contain userAddress (string or null), + * href (string or null), storageApi (string or null), token (string + * or null), and/or properties (the JSON-parsed properties object + * from the user's WebFinger record, see section 10 of + * http://tools.ietf.org/html/draft-dejong-remotestorage-03 + * or null). + * Fields that are not included (i.e. `undefined`), stay at + * their current value. To set a field, include that field + * with a `string` value. To reset a field, for instance when + * the user disconnected their storage, or you found that the + * token you have has expired, simply set that field to `null`. + */ + configure(settings) { + if (typeof settings !== 'object') { + throw new Error('WireClient configure settings parameter should be an object'); + } + if (typeof settings.userAddress !== 'undefined') { + this.userAddress = settings.userAddress; + } + if (typeof settings.href !== 'undefined') { + this.href = settings.href; + } + if (typeof settings.storageApi !== 'undefined') { + this.storageApi = settings.storageApi; + } + if (typeof settings.token !== 'undefined') { + this.token = settings.token; + } + if (typeof settings.properties !== 'undefined') { + this.properties = settings.properties; + } + if (typeof this.storageApi === 'string') { + const _storageApi = STORAGE_APIS[this.storageApi] || API_HEAD; + this.supportsRevs = _storageApi >= API_00; + } + if (this.href && this.token) { + this.connected = true; + this.online = true; + this._emit('connected'); + } + else { + this.connected = false; + } + if (hasLocalStorage) { + localStorage[SETTINGS_KEY] = JSON.stringify({ + userAddress: this.userAddress, + href: this.href, + storageApi: this.storageApi, + token: this.token, + properties: this.properties + }); + } + } + get(path, options = {}) { + if (!this.connected) { + return Promise.reject('not connected (path: ' + path + ')'); + } + const headers = {}; + if (this.supportsRevs) { + if (options.ifNoneMatch) { + headers['If-None-Match'] = this.addQuotes(options.ifNoneMatch); + } + } + // commenting it out as this is doing nothing and jshint is complaining -les + // else if (options.ifNoneMatch) { + // let oldRev = this._revisionCache[path]; + // } + return this._request('GET', this.href + (0, util_1.cleanPath)(path), this.token, headers, undefined, this.supportsRevs, this._revisionCache[path]) + .then((r) => { + if (!(0, util_1.isFolder)(path)) { + return Promise.resolve(r); + } + let itemsMap = {}; + if (typeof (r.body) !== 'undefined') { + try { + r.body = JSON.parse(r.body); + } + catch (e) { + return Promise.reject('Folder description at ' + this.href + (0, util_1.cleanPath)(path) + ' is not JSON'); + } + } + if (r.statusCode === 200 && typeof (r.body) === 'object') { + // New folder listing received + if (Object.keys(r.body).length === 0) { + // Empty folder listing of any spec + r.statusCode = 404; + } + else if (isFolderDescription(r.body)) { + // >= 02 spec + for (const item in r.body.items) { + this._revisionCache[path + item] = r.body.items[item].ETag; + } + itemsMap = r.body.items; + } + else { + // < 02 spec + Object.keys(r.body).forEach((key) => { + this._revisionCache[path + key] = r.body[key]; + itemsMap[key] = { 'ETag': r.body[key] }; + }); + } + r.body = itemsMap; + return Promise.resolve(r); + } + else { + return Promise.resolve(r); + } + }); + } + put(path, body, contentType, options = {}) { + if (!this.connected) { + return Promise.reject('not connected (path: ' + path + ')'); + } + if ((!contentType.match(/charset=/)) && (body instanceof ArrayBuffer || (0, requests_1.isArrayBufferView)(body))) { + contentType += '; charset=binary'; + } + const headers = { 'Content-Type': contentType }; + if (this.supportsRevs) { + if (options.ifMatch) { + headers['If-Match'] = this.addQuotes(options.ifMatch); + } + if (options.ifNoneMatch) { + headers['If-None-Match'] = this.addQuotes(options.ifNoneMatch); + } + } + return this._request('PUT', this.href + (0, util_1.cleanPath)(path), this.token, headers, body, this.supportsRevs); + } + delete(path, options = {}) { + if (!this.connected) { + throw new Error('not connected (path: ' + path + ')'); + } + if (!options) { + options = {}; + } + const headers = {}; + if (this.supportsRevs) { + if (options.ifMatch) { + headers['If-Match'] = this.addQuotes(options.ifMatch); + } + } + return this._request('DELETE', this.href + (0, util_1.cleanPath)(path), this.token, headers, undefined, this.supportsRevs); + } + static _rs_init(remoteStorage) { + remoteStorage.remote = new WireClient(remoteStorage); + remoteStorage.remote.online = true; + } + static _rs_supported() { + return typeof fetch === 'function' || typeof XMLHttpRequest === 'function'; + } + static _rs_cleanup() { + if (hasLocalStorage) { + delete localStorage[SETTINGS_KEY]; + } + } +} +(0, util_1.applyMixins)(WireClient, [eventhandling_1.default]); +module.exports = WireClient; + + +/***/ }), + +/***/ 0: +/*!************************************!*\ + !*** multi ./src/remotestorage.ts ***! + \************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__(/*! ./src/remotestorage.ts */"./src/remotestorage.ts"); + + +/***/ }) + +/******/ }); +}); //# sourceMappingURL=remotestorage.js.map \ No newline at end of file diff --git a/release/remotestorage.js.map b/release/remotestorage.js.map index 6ca60b14b..b4e6abbe6 100644 --- a/release/remotestorage.js.map +++ b/release/remotestorage.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack://RemoteStorage/webpack/universalModuleDefinition","webpack://RemoteStorage/webpack/bootstrap","webpack://RemoteStorage/./src/util.ts","webpack://RemoteStorage/./src/log.ts","webpack://RemoteStorage/./src/eventhandling.ts","webpack://RemoteStorage/./src/config.ts","webpack://RemoteStorage/./src/authorize.ts","webpack://RemoteStorage/./src/unauthorized-error.ts","webpack://RemoteStorage/(webpack)/buildin/global.js","webpack://RemoteStorage/./src/requests.ts","webpack://RemoteStorage/./src/baseclient.ts","webpack://RemoteStorage/./src/remote.ts","webpack://RemoteStorage/./src/sync-error.ts","webpack://RemoteStorage/./src/cachinglayer.ts","webpack://RemoteStorage/./src/access.ts","webpack://RemoteStorage/./src/caching.ts","webpack://RemoteStorage/./src/googledrive.ts","webpack://RemoteStorage/./src/dropbox.ts","webpack://RemoteStorage/./src/discover.ts","webpack://RemoteStorage/./src/env.ts","webpack://RemoteStorage/./src/remotestorage.ts","webpack://RemoteStorage/./node_modules/buffer/index.js","webpack://RemoteStorage/./node_modules/base64-js/index.js","webpack://RemoteStorage/./node_modules/ieee754/index.js","webpack://RemoteStorage/./node_modules/isarray/index.js","webpack://RemoteStorage/./node_modules/tv4/tv4.js","webpack://RemoteStorage/./src/types.ts","webpack://RemoteStorage/./src/schema-not-found-error.ts","webpack://RemoteStorage/./src/revisioncache.ts","webpack://RemoteStorage/./node_modules/webfinger.js/src/webfinger.js","webpack://RemoteStorage/./node_modules/xhr2/lib/browser.js","webpack://RemoteStorage/./src/features.ts","webpack://RemoteStorage/./src/syncedgetputdelete.ts","webpack://RemoteStorage/./src/wireclient.ts","webpack://RemoteStorage/./src/sync.ts","webpack://RemoteStorage/./src/indexeddb.ts","webpack://RemoteStorage/./src/localstorage.ts","webpack://RemoteStorage/./src/inmemorystorage.ts"],"names":["root","factory","exports","module","define","amd","this","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","logError","error","console","message","stack","globalContext","window","self","global","getGlobalContext","extend","args","target","Array","slice","forEach","source","containingFolder","path","replace","isFolder","isDocument","baseName","parts","split","length","cleanPath","map","encodeURIComponent","join","bindAll","equal","a","b","seen","toString","ArrayBuffer","Uint8Array","seenArg","indexOf","push","deepClone","obj","undefined","clone","JSON","parse","stringify","_fixArrayBuffers","srcObj","dstObj","isArray","field","byteLength","srcArr","Int8Array","set","pathsFromRoot","paths","pop","localStorageAvailable","context","localStorage","setItem","removeItem","getJSONFromLocalStorage","getItem","e","shouldBeTreatedAsBinary","content","mimeType","match","test","getTextFromArrayBuffer","arrayBuffer","encoding","Promise","resolve","Blob","buffer","Buffer","from","blob","gc","BlobBuilder","WebKitBlobBuilder","bb","append","getBlob","fileReader","FileReader","addEventListener","evt","result","onloadend","readAsText","toBase64","str","numChar","randomBytes","crypto","getRandomValues","charSet","randomChar","byte","codeVerifier","charsAsBytes","ch","charCodeAt","sha256hash","subtle","digest","codeChallenge","btoa","String","fromCharCode","apply","state","derivedCtor","baseCtors","baseCtor","getOwnPropertyNames","getOwnPropertyDescriptor","logging","log","additionalEvents","evName","_addEvent","eventName","handler","Error","_validateEvent","_handlers","hl","splice","on","event","_emit","config","cache","changeEvents","local","remote","conflict","cordovaRedirectUri","backgroundSyncInterval","disableFeatures","discoveryTimeout","isBackground","requestTimeout","syncInterval","onFeaturesLoaded","extractParams","url","location","Authorize","getLocation","href","queryParam","URL","searchParams","hashPos","urlFragment","substring","includes","reduce","params","kvs","kv","stateValue","decodeURIComponent","encodedData","substr","atob","RegExp","remoteStorage","options","authURL","scope","redirectUri","clientId","response_type","backend","discoveryData","userAddress","storageApi","properties","redirect","hash","buildOAuthURL","openWindow","then","authResult","configure","token","access_token","setLocation","rs","refreshToken","tokenType","formValues","URLSearchParams","grant_type","client_id","refresh_token","xhr","requestWithTimeout","TOKEN_URL","headers","body","responseType","status","response","expires_in","settings","token_type","document","removeEventListener","IMPLIED_FAKE_TOKEN","reject","newWindow","open","handleExit","closed","close","_rs_init","authParamsUsed","code","rsDiscovery","remotestorage","connect","sessionStorage","origin","pathname","redirect_uri","code_verifier","statusText","fetchTokens","stopWaitingForToken","UnauthorizedError","super","g","Function","serverMs","parseInt","getResponseHeader","Math","max","min","round","random","isArrayBufferView","ArrayBufferView","arrayBufferViews","Int16Array","Uint16Array","Int32Array","Uint32Array","Float32Array","Float64Array","method","fetch","abortController","AbortController","timeoutId","timeoutPromise","_resolve","setTimeout","abort","syntheticXhr","responseHeaders","networkPromise","signal","headerName","toUpperCase","readyState","responseURL","json","text","processedBody","responseText","finally","clearTimeout","race","_fetchRequestWithTimeout","XMLHttpRequest","timedOut","timer","setRequestHeader","onload","onerror","send","_xhrRequestWithTimeout","BaseClient","storage","base","schemas","configurable","Types","inScope","moduleName","makePath","getModuleNameFromBase","addEvents","onChange","_fireChange","maxAge","statusCode","keys","calls","all","data","contentType","revision","access","checkPathPermission","warn","put","typeAlias","_attachType","validationResult","validate","valid","exc","delete","connected","strategy","caching","flush","alias","uriOrSchema","schema","uri","_defaultTypeURI","declare","getSchema","validateResult","resolveAlias","fieldNamePrefix","exec","applyMixins","RemoteBase","SyncError","originalError","getLatest","node","itemsMap","common","isOutdated","nodes","nodeVersion","timestamp","Date","getTime","makeNode","updateFolderNodeWithItemName","itemName","CachingLayer","_updateNodesRunning","_updateNodesQueued","queueGetRequest","getNodes","objs","_updateNodes","nodePaths","len","nodePath","previous","previousBody","previousContentType","_getAllDescendentPaths","_emitChange","oldValue","newValue","setNodes","forAllNodes","latest","oldContentType","newContentType","diffHandler","_processNodes","_doUpdateNodes","promise","cb","existingNodes","_emitChangeEvents","err","nextJob","shift","events","allPaths","reset","scopeModeMap","scopes","_scopeNameForParameter","_adjustRootPaths","savedMap","claim","actualMode","checkPermission","_getModuleName","rootPaths","moduleMatch","newScope","storageType","type","pendingActivations","_rootPaths","activateHandler","checkPath","BASE_URL","SETTINGS_KEY","hasLocalStorage","metaTitleFromFileName","filename","parentPath","googleDrivePath","FileIdCache","_items","item","now","v","GoogleDrive","online","_fileIdCache","writeSettingsToCache","handleError","info","user","emailAddress","catch","setBackend","authorize","_getFolder","_getFile","fullPath","putDone","meta","etagWithoutQuotes","stripQuotes","etag","_getFileId","id","ifNoneMatch","_updateFile","_createFile","_getMeta","ifMatch","_request","resp","metadata","addQuotes","_getParentId","parentId","title","parents","kind","downloadUrl","exportLinks","query","items","labels","trashed","ETag","fileSize","foldername","_createFolder","isForbiddenRequestMethod","success","apiKeys","googledrive","_origRemote","_origBaseClientGetItemURL","getItemURL","FOLDER_URL","CONTINUE_URL","getDropboxPath","PATH_PREFIX","charsToEncode","httpHeaderSafeJson","compareApiError","expect","error_summary","isBinaryData","Dropbox","_initialFetchDone","dropbox","appKey","_revCache","_fetchDeltaCursor","_fetchDeltaPromise","_itemRefs","hookIt","generateCodeVerifier","code_challenge","code_challenge_method","token_access_type","email","revCache","processResponse","listing","entries","isDir","path_display","date","server_modified","rev","size","toUTCString","has_more","loadNext","cursor","nextListing","assign","savedRev","fetchDelta","mime","_shareIfNeeded","needsMetadata","uploadParams","_getMetadata","_uploadSimple","_deleteSimple","share","_getSharedLink","link","numAttempts","refreshAccessToken","retryAfterMs","requestBody","recursive","include_deleted","responseBody","deactivatePropagation","entry","activatePropagation","update","mute","direct_only","links","unHookRemote","_dropboxOrigSync","sync","unHookSync","unHookGetItemURL","unHookSyncCycle","unHookIt","hookSync","_dropboxOrigSyncCycle","syncCycle","hookRemote","hookSyncCycle","hookGetItemURL","haveXMLHttpRequest","cachedInfo","Discover","tls_only","uri_fallback","request_timeout","lookup","idx","DiscoveryError","constructor","_rs_supported","_rs_cleanup","Env","setBrowserPrefixedNames","visibilityChangeEvent","setVisibility","hidden","hiddenProperty","goBackground","goForeground","emitUnauthorized","isValidInterval","interval","RemoteStorage","cfg","_pending","_cleanups","_pathHandlers","change","_init","loadFeatures","features","loadFeature","featureSupported","featureDone","featuresDone","featuresLoaded","featureInitialized","featureFailed","hasFeature","_setCachingModule","_collectCleanupFunctions","_fireReady","initFeature","_setGPD","_pendingGPD","origOn","_allLoaded","fireInitial","loadModules","addModule","setStorageType","scopeParameter","cordova","InAppBrowser","impliedauth","oneDone","cleanup","cleanupResult","what","validTypes","ApiKeyType","GOOGLE","DROPBOX","every","impl","wrap","func","methodName","methodArguments","pending","_dispatchEvent","pl","ev","relativePath","timeout","stopped","_syncTimer","getCurrentSyncInterval","syncStopped","moduleBuilder","builder","instance","_loadModule","camelizedName","Unauthorized","util","base64","ieee754","kMaxLength","TYPED_ARRAY_SUPPORT","createBuffer","that","RangeError","__proto__","arg","encodingOrOffset","allocUnsafe","TypeError","array","byteOffset","fromArrayLike","fromArrayBuffer","string","isEncoding","actual","write","fromString","isBuffer","checked","copy","val","fromObject","assertSize","isView","loweredCase","utf8ToBytes","base64ToBytes","toLowerCase","slowToString","start","end","hexSlice","utf8Slice","asciiSlice","latin1Slice","base64Slice","utf16leSlice","swap","bidirectionalIndexOf","dir","isNaN","arrayIndexOf","lastIndexOf","arr","indexSize","arrLength","valLength","read","buf","readUInt16BE","foundIndex","found","j","hexWrite","offset","Number","remaining","strLen","parsed","utf8Write","blitBuffer","asciiWrite","byteArray","asciiToBytes","latin1Write","base64Write","ucs2Write","units","hi","lo","utf16leToBytes","fromByteArray","res","secondByte","thirdByte","fourthByte","tempCodePoint","firstByte","codePoint","bytesPerSequence","codePoints","decodeCodePointsArray","SlowBuffer","alloc","INSPECT_MAX_BYTES","foo","subarray","typedArraySupport","poolSize","_augment","species","fill","allocUnsafeSlow","_isBuffer","compare","x","y","concat","list","pos","swap16","swap32","swap64","arguments","equals","inspect","thisStart","thisEnd","thisCopy","targetCopy","isFinite","toJSON","_arr","ret","out","toHex","bytes","checkOffset","ext","checkInt","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","writeDouble","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt8","readUInt16LE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","writeUIntBE","writeUInt8","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","targetStart","INVALID_BASE64_RE","Infinity","leadSurrogate","toByteArray","trim","stringtrim","base64clean","src","dst","b64","lens","getLens","validLen","placeHoldersLen","tmp","Arr","_byteLength","curByte","revLookup","uint8","extraBytes","len2","encodeChunk","num","output","isLE","mLen","nBytes","eLen","eMax","eBias","nBits","NaN","rt","abs","LN2","hasDontEnumBug","dontEnums","dontEnumsLength","propertyIsEnumerable","prop","F","vArg","searchElement","k","isFrozen","uriTemplateGlobalModifiers","uriTemplateSuffices","notReallyPercentEncode","encodeURI","doubleEncoded","uriTemplateSubstitution","spec","modifier","charAt","separator","prefix","shouldEscape","showVariables","trimEmptyString","varNames","varList","varSpecs","varSpecMap","varName","truncate","suffices","varSpec","subFunction","valueFunction","startIndex","first","substitution","UriTemplate","template","textParts","prefixes","substitutions","part","remainder","funcs","fillFromObject","ValidatorContext","parent","collectMultiple","errorReporter","checkRecursive","trackUnknownProperties","missing","missingMap","formatValidators","errors","collectError","returnError","scanned","scannedFrozen","scannedFrozenSchemas","scannedFrozenValidationErrors","validatedSchemasKey","validationErrorsKey","knownPropertyPaths","unknownPropertyPaths","defaultErrorReporter","definedKeywords","recursiveCompare","A","B","defineKeyword","keyword","keywordFunction","createError","messageParams","dataPath","schemaPath","subErrors","ValidationError","prefixErrors","prefixWith","banUnknownProperties","unknownPath","ErrorCodes","UNKNOWN_PROPERTY","addFormat","format","validator","resolveRefs","urlHistory","CIRCULAR_REFERENCE","urls","baseUrl","fragment","pointerPath","component","searchSchemas","testUrl","isTrustedUrl","getDocumentUri","addSchema","normSchema","getSchemaMap","getSchemaUris","filterRegExp","getMissingUris","dropSchemas","validateAll","dataPathParts","schemaPathParts","dataPointerPath","topLevel","frozenIndex","startErrorCount","scannedFrozenSchemaIndex","scannedSchemasIndex","schemaIndex","frozenSchemaIndex","errorCount","validateBasic","validateNumeric","validateString","validateArray","validateObject","validateCombinations","validateHypermedia","validateFormat","validateDefinedKeywords","dataPart","schemaPart","errorMessage","FORMAT_CUSTOM","validationFunctions","KEYWORD_CUSTOM","validateType","validateEnum","dataType","allowedTypes","INVALID_TYPE","expected","ENUM_MISMATCH","validateMultipleOf","validateMinMax","validateNaN","CLOSE_ENOUGH_LOW","CLOSE_ENOUGH_HIGH","parseURI","protocol","authority","host","hostname","port","search","resolveUrl","input","baseUri","language","errorMessages","languages","messageTemplate","ErrorMessagesDefault","whole","subValue","multipleOf","divisibleBy","NUMBER_MULTIPLE_OF","minimum","NUMBER_MINIMUM","exclusiveMinimum","NUMBER_MINIMUM_EXCLUSIVE","maximum","NUMBER_MAXIMUM","exclusiveMaximum","NUMBER_MAXIMUM_EXCLUSIVE","NUMBER_NOT_A_NUMBER","validateStringLength","validateStringPattern","minLength","STRING_LENGTH_SHORT","maxLength","STRING_LENGTH_LONG","pattern","regexp","flags","literal","STRING_PATTERN","validateArrayLength","validateArrayUniqueItems","validateArrayItems","minItems","ARRAY_LENGTH_SHORT","maxItems","ARRAY_LENGTH_LONG","uniqueItems","ARRAY_UNIQUE","match1","match2","additionalItems","ARRAY_ADDITIONAL_ITEMS","validateObjectMinMaxProperties","validateObjectRequiredProperties","validateObjectProperties","validateObjectDependencies","minProperties","OBJECT_PROPERTIES_MINIMUM","propertyCount","maxProperties","OBJECT_PROPERTIES_MAXIMUM","required","OBJECT_REQUIRED","keyPointerPath","foundMatch","patternProperties","patternKey","additionalProperties","OBJECT_ADDITIONAL_PROPERTIES","dependencies","depKey","dep","OBJECT_DEPENDENCY_KEY","requiredKey","validateAllOf","validateAnyOf","validateOneOf","validateNot","allOf","subSchema","anyOf","oldUnknownPropertyPaths","oldKnownPropertyPaths","errorAtEnd","knownKey","unknownKey","ANY_OF_MISSING","oneOf","validIndex","ONE_OF_MULTIPLE","index1","index2","ONE_OF_MISSING","not","oldErrorCount","notErrors","NOT_PASSED","ldo","rel","allPresent","ErrorCodeLookup","stacktrace","dataPrefix","schemaPrefix","tv4","createApi","currentLanguage","customErrorReporter","api","setErrorReporter","reporter","addLanguage","messageMap","rootCode","freshApi","def","validateMultiple","defineError","codeName","codeNumber","defaultMessage","langCode","errorCodes","BaseClientTypes","uris","aliases","fullAlias","extends","extendedAlias","extendedUri","ml","SchemaNotFound","defaultValue","_itemsRev","_storage","_canPropagate","stored","_updateParentFolderItemRev","_propagate","_generateFolderRev","files","sort","_hashCode","parentFolder","_getParentFolder","parentFolderItemsRev","hashItems","newRev","_generateHash","folder","itemsRev","hashItem","LINK_URI_MAPS","LINK_PROPERTIES","URIS","generateErrorObject","WebFinger","webfist_fallback","__fetchJRD","errorHandler","successHandler","__fetchJRD_fetch","__fetchJRD_XHR","webfinger","ok","__isValidJSON","handlerSpent","__processState","isSecure","__makeRequest","onreadystatechange","ontimeout","__isLocalhost","__processJRD","JRD","parsedJRD","request","props","address","uri_index","__buildURL","__fallbackChecks","__call","webfist","lookupLink","Features","readyFired","featureModules","feature","featureName","supported","initResult","init","some","cachingLayer","_bindChange","_processPending","shareFirst","SyncedGetPutDelete","getSyncInterval","_wrapBusyDone","STORAGE_APIS","WireClient","_revisionCache","readSettings","getEtag","fakeRevision","isSuccessStatus","charset","charsetMatch","determineCharset","textContent","_storageApi","supportsRevs","syncCycleCb","syncOnConnect","taskFor","action","nodeChanged","hasCommonRevision","Sync","_tasks","_running","_timeStarted","numThreads","onDiff","addTask","doTasks","onActivate","force02","contentLength","corruptItemsMap","corruptRevision","isCorrupt","needsFetch","needsPush","inConflict","needsRefresh","getParentPath","deleteChildPathsFromTasks","isStaleChild","needsRemotePut","needsRemoteDelete","hasNoRemoteChanges","lastCommonValue","lastCommonContentType","mergeMutualDeletion","autoMergeFolder","autoMergeDocument","changedNodes","missingChildren","recurse","childName","cachingStrategy","autoMerge","commonItem","localItem","parentNode","deleteRemoteTrees","changedObjs2","subPaths","collectSubPaths","changedNodes2","bodyOrItemsMap","pathsFromRootArr","collectMissingChildren","toBeSaved","successful","unAuth","notFound","changed","networkProblems","series","completeFetch","dataFromFetch","corruptServerItemsMap","markChildren","updateCommonTimestamp","interpretStatus","handleGetResponse","completePush","dealWithFailure","task","handleResponse","completed","collectTasks","hasTasks","done","numToHave","numAdded","numToAdd","doTask","finishTask","alsoCheckRefresh","collectDiffTasks","numDiffs","collectRefreshTasks","env","isBrowser","handleChange","isForeground","handleVisibility","startSync","stopSync","DEFAULT_DB","IndexedDB","database","db","getsRunning","putsRunning","changesQueued","changesRunning","commitSlownessWarning","misses","fromCache","getNodesFromDb","maybeFlush","flushChangesQueued","setInterval","clearInterval","setNodesInDb","transaction","objectStore","retrievedNodes","onsuccess","oncomplete","onabort","nodesStore","startTime","callback","dbName","clean","other","openCursor","migrate","continue","closeDB","req","indexedDB","onupgradeneeded","oldVersion","newVersion","createObjectStore","keyPath","objectStoreNames","contains","databaseName","deleteDatabase","poorIndexedDbSupport","navigator","userAgent","check","NODES_PREFIX","isRemoteStorageKey","LocalStorage","InMemoryStorage"],"mappings":"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","file":"remotestorage.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"RemoteStorage\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"RemoteStorage\"] = factory();\n\telse\n\t\troot[\"RemoteStorage\"] = factory();\n})(this, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 18);\n","// Reusable utility functions\n\n/**\n * Takes an object and its copy as produced by the _deepClone function\n * below, and finds and fixes any ArrayBuffers that were cast to `{}` instead\n * of being cloned to new ArrayBuffers with the same content.\n *\n * It recurses into sub-objects, but skips arrays if they occur.\n */\nfunction _fixArrayBuffers(srcObj: object, dstObj: object) {\n if (typeof (srcObj) !== 'object' || Array.isArray(srcObj) || srcObj === null) {\n return;\n }\n for (const field in srcObj) {\n if (typeof (srcObj[field]) === 'object' && srcObj[field] !== null) {\n if (srcObj[field].toString() === '[object ArrayBuffer]') {\n dstObj[field] = new ArrayBuffer(srcObj[field].byteLength);\n const srcArr = new Int8Array(srcObj[field]);\n const dstArr = new Int8Array(dstObj[field]);\n dstArr.set(srcArr);\n } else {\n _fixArrayBuffers(srcObj[field], dstObj[field]);\n }\n }\n }\n}\n\nexport const logError = (error: string | Error): void => {\n if (typeof (error) === 'string') {\n console.error(error);\n } else {\n console.error(error.message, error.stack);\n }\n};\n\nexport const globalContext = (typeof (window) !== 'undefined' ? window : (typeof self === 'object' ? self : global));\n\nexport const getGlobalContext = (): any => {\n return (typeof (window) !== 'undefined' ? window : (typeof self === 'object' ? self : global));\n};\n\n// TODO Remove in favor of modern JS:\n// `const mergedObject = { ...obj1, ..obj2 }`\nexport const extend = (...args): unknown => {\n const target = args[0];\n const sources = Array.prototype.slice.call(args, 1);\n sources.forEach(function (source) {\n for (const key in source) {\n target[key] = source[key];\n }\n });\n return target;\n};\n\nexport const containingFolder = (path: string): string => {\n if (path === '') {\n return '/';\n }\n if (!path) {\n throw \"Path not given!\";\n }\n\n return path.replace(/\\/+/g, '/')\n .replace(/[^\\/]+\\/?$/, '');\n};\n\nexport const isFolder = (path: string): boolean => {\n return path.slice(-1) === '/';\n};\n\nexport const isDocument = (path: string): boolean => {\n return !isFolder(path);\n};\n\nexport const baseName = (path: string): string => {\n const parts = path.split('/');\n if (isFolder(path)) {\n return parts[parts.length - 2] + '/';\n } else {\n return parts[parts.length - 1];\n }\n};\n\nexport const cleanPath = (path: string): string => {\n return path.replace(/\\/+/g, '/')\n .split('/').map(encodeURIComponent).join('/')\n .replace(/'/g, '%27');\n};\n\nexport const bindAll = (object: object) => {\n for (const key in this) {\n if (typeof (object[key]) === 'function') {\n object[key] = object[key].bind(object);\n }\n }\n};\n\nexport const equal = (a: any, b: any, seen = []): boolean => {\n let key;\n\n if (typeof (a) !== typeof (b)) {\n return false;\n }\n\n if (typeof (a) === 'number' || typeof (a) === 'boolean' || typeof (a) === 'string') {\n return a === b;\n }\n\n if (typeof (a) === 'function') {\n return a.toString() === b.toString();\n }\n\n if (a instanceof ArrayBuffer && b instanceof ArrayBuffer) {\n // Without the following conversion the browsers wouldn't be able to\n // tell the ArrayBuffer instances apart.\n a = new Uint8Array(a);\n b = new Uint8Array(b);\n }\n\n // If this point has been reached, a and b are either arrays or objects.\n\n if (a instanceof Array) {\n if (a.length !== b.length) {\n return false;\n }\n\n for (let i = 0, c = a.length; i < c; i++) {\n if (!equal(a[i], b[i], seen)) {\n return false;\n }\n }\n } else {\n // Check that keys from a exist in b\n for (key in a) {\n if (a.hasOwnProperty(key) && !(key in b)) {\n return false;\n }\n }\n\n // Check that keys from b exist in a, and compare the values\n for (key in b) {\n if (!b.hasOwnProperty(key)) {\n continue;\n }\n\n if (!(key in a)) {\n return false;\n }\n\n let seenArg;\n\n if (typeof (b[key]) === 'object') {\n if (seen.indexOf(b[key]) >= 0) {\n // Circular reference, don't attempt to compare this object.\n // If nothing else returns false, the objects match.\n continue;\n }\n\n seenArg = seen.slice();\n seenArg.push(b[key]);\n }\n\n if (!equal(a[key], b[key], seenArg)) {\n return false;\n }\n }\n }\n\n return true;\n};\n\nexport const deepClone = (obj: any): any => {\n if (obj === undefined) {\n return undefined;\n } else {\n const clone = JSON.parse(JSON.stringify(obj));\n _fixArrayBuffers(obj, clone);\n return clone;\n }\n};\n\nexport const pathsFromRoot = (path: string): string[] => {\n const paths = [path];\n const parts = path.replace(/\\/$/, '').split('/');\n\n while (parts.length > 1) {\n parts.pop();\n paths.push(parts.join('/') + '/');\n }\n return paths;\n};\n\nexport const localStorageAvailable = (): boolean => {\n const context = getGlobalContext();\n\n if (!('localStorage' in context)) {\n return false;\n }\n\n try {\n context.localStorage.setItem('rs-check', '1');\n context.localStorage.removeItem('rs-check');\n return true;\n } catch (error) {\n return false;\n }\n};\n\n/**\n * Extract and parse JSON data from localStorage.\n *\n * @param {string} key - localStorage key\n *\n * @returns {object} parsed object or undefined\n */\nexport const getJSONFromLocalStorage = (key: string): { [key: string]: any } => {\n const context = getGlobalContext() as Window;\n\n try {\n return JSON.parse(context.localStorage.getItem(key));\n } catch (e) {\n // no JSON stored\n }\n};\n\n/**\n * Decide if data should be treated as binary based on the content (presence of non-printable characters\n * or replacement character) and content-type.\n *\n * @param {string} content - The data\n * @param {string} mimeType - The data's content-type\n *\n * @returns {boolean}\n */\nexport const shouldBeTreatedAsBinary = (content: string | ArrayBuffer, mimeType: string): boolean => {\n // eslint-disable-next-line no-control-regex\n return !!((mimeType && mimeType.match(/charset=binary/)) || /[\\x00-\\x08\\x0E-\\x1F\\uFFFD]/.test(content as string));\n};\n\n/**\n * Read data from an ArrayBuffer and return it as a string\n * @param {ArrayBuffer} arrayBuffer\n * @param {string} encoding\n * @returns {Promise} Resolves with a string containing the data\n */\nexport const getTextFromArrayBuffer = (arrayBuffer: ArrayBuffer, encoding): Promise => {\n return new Promise((resolve/*, reject*/) => {\n if (typeof Blob === 'undefined') {\n const buffer = Buffer.from(arrayBuffer);\n resolve(buffer.toString(encoding));\n } else {\n let blob;\n const gc = globalContext as any;\n // TODO fix as BlobBuilder is not available in all browsers\n // @see https://developer.mozilla.org/en-US/docs/Web/API/BlobBuilder\n gc.BlobBuilder = gc.BlobBuilder || gc.WebKitBlobBuilder;\n if (typeof gc.BlobBuilder !== 'undefined') {\n const bb = new gc.BlobBuilder();\n bb.append(arrayBuffer);\n blob = bb.getBlob();\n } else {\n blob = new Blob([arrayBuffer]);\n }\n\n const fileReader = new FileReader();\n if (typeof fileReader.addEventListener === 'function') {\n fileReader.addEventListener('loadend', function (evt) {\n resolve(evt.target.result);\n });\n } else {\n fileReader.onloadend = function (evt) {\n resolve(evt.target.result);\n };\n }\n fileReader.readAsText(blob, encoding);\n }\n });\n};\n\n/**\n * Encode string in base64\n * @param {String} str\n * @returns {String} base64-encoded string\n */\nexport const toBase64 = (str: string): string => {\n const context = getGlobalContext();\n if ('btoa' in context) {\n return context['btoa'](str);\n } else {\n return Buffer.from(str).toString('base64');\n }\n};\n\n/**\n * Generates values required for OAuth2 PKCE in a cryptographically secure manner.\n * @param {number} [numChar=128] - length of codeVerifier to generate; from 43 to 128\n *\n * @typedef {Object} PkceValues\n * @property {string} codeVerifier - 43 to 128 chars from the 66-char set\n * @property {string} codeChallenge - verifier hashed & base-64 URL encoded\n * @property {string} state - a separate random value. Should be used to check redirect_uri.\n * @returns PkceValues\n */\nexport async function generateCodeVerifier(numChar = 128) {\n const randomBytes = new Uint8Array(numChar);\n crypto.getRandomValues(randomBytes);\n\n const charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';\n const randomChar = Array.from(randomBytes).map(byte => charSet[byte % charSet.length]);\n const codeVerifier = randomChar.join('');\n\n const charsAsBytes = Uint8Array.from(randomChar.map(ch => ch.charCodeAt(0)));\n const sha256hash = await crypto.subtle.digest('SHA-256', charsAsBytes);\n const codeChallenge = base64Urlencode(sha256hash);\n\n crypto.getRandomValues(randomBytes);\n const stateRandomChar = Array.from(randomBytes).map(byte => charSet[byte % charSet.length]);\n const state = stateRandomChar.join('');\n\n return {codeVerifier, codeChallenge, state};\n}\n\nfunction base64Urlencode(str) {\n return btoa(String.fromCharCode.apply(null,\n new Uint8Array(str)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n}\n\n/*\n * Apply mixins to an object\n *\n * https://www.typescriptlang.org/docs/handbook/mixins.html\n *\n * @param {object} Parent object\n * @param {Array} Mixins to apply methods from\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function applyMixins(derivedCtor: any, baseCtors: any[]): void {\n baseCtors.forEach(baseCtor => {\n Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {\n Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name));\n });\n });\n}\n","import config from './config';\n\n/**\n * Log using console.log, when remoteStorage logging is enabled.\n *\n * You can enable logging with ``RemoteStorage#enableLog``.\n *\n * (You can also enable logging during remoteStorage object creation. See:\n * {@link RemoteStorage}).\n */\nfunction log(...args): void {\n if (config.logging) {\n // eslint-disable-next-line no-console\n console.log(...args);\n }\n}\n\nexport = log;\n","import log from './log';\nimport { EventHandler } from './interfaces/event_handling';\n\nclass EventHandling {\n _handlers: { [key: string]: EventHandler[] };\n\n /**\n * Register event names\n *\n * TODO see if necessary, or can be done on the fly in addEventListener\n */\n addEvents(additionalEvents: string[]): void {\n additionalEvents.forEach(evName => this._addEvent(evName));\n }\n\n /**\n * Install an event handler for the given event name\n */\n addEventListener (eventName: string, handler: EventHandler): void {\n // Check type for public consumption of API\n if (typeof (eventName) !== 'string') {\n throw new Error('Argument eventName should be a string');\n }\n if (typeof (handler) !== 'function') {\n throw new Error('Argument handler should be a function');\n }\n log('[EventHandling] Adding event listener', eventName);\n this._validateEvent(eventName);\n this._handlers[eventName].push(handler);\n }\n\n /*\n * Alias for addEventListener\n */\n on (eventName: string, handler: EventHandler): void {\n return this.addEventListener(eventName, handler);\n }\n\n /**\n * Remove a previously installed event handler\n */\n removeEventListener (eventName: string, handler: EventHandler): void {\n this._validateEvent(eventName);\n const hl = this._handlers[eventName].length;\n for (let i = 0; i < hl; i++) {\n if (this._handlers[eventName][i] === handler) {\n this._handlers[eventName].splice(i, 1);\n return;\n }\n }\n }\n\n _emit (eventName: string, ...args: unknown[]): void {\n this._validateEvent(eventName);\n this._handlers[eventName].slice().forEach((handler) => {\n handler.apply(this, args);\n });\n }\n\n _validateEvent (eventName: string): void {\n if (!(eventName in this._handlers)) {\n throw new Error(\"Unknown event: \" + eventName);\n }\n }\n\n _delegateEvent (eventName: string, target): void {\n target.on(eventName, (event) => {\n this._emit(eventName, event);\n });\n }\n\n _addEvent (eventName: string): void {\n if (typeof this._handlers === 'undefined') {\n this._handlers = {};\n }\n this._handlers[eventName] = [];\n }\n}\n\nexport = EventHandling;\n","/**\n * The default config, merged with the object passed to the constructor of the\n * RemoteStorage object\n */\nconst config = {\n cache: true,\n changeEvents: {\n local: true,\n window: false,\n remote: true,\n conflict: true\n },\n cordovaRedirectUri: undefined,\n logging: false,\n modules: [],\n // the following are not public and will probably be moved away from the\n // default config\n backgroundSyncInterval: 60000,\n disableFeatures: [],\n discoveryTimeout: 10000,\n isBackground: false,\n requestTimeout: 30000,\n syncInterval: 10000\n};\n\nexport = config;\n","import log from './log';\nimport RemoteStorage from './remotestorage';\nimport {localStorageAvailable, globalContext, toBase64} from './util';\nimport UnauthorizedError from './unauthorized-error';\nimport { EventHandler } from './interfaces/event_handling';\nimport {requestWithTimeout} from \"./requests\";\nimport {AuthorizeOptions} from \"./interfaces/authorize_options\";\nimport {Remote} from \"./remote\";\n\n\ninterface AuthResult {\n access_token?: string;\n refresh_token?: string;\n code?: string;\n rsDiscovery?: object;\n error?: string;\n remotestorage?: string;\n state?: string;\n}\n\ninterface InAppBrowserEvent extends Event {\n type: 'loadstart'|'loadstop'|'loaderror'|'message'|'exit';\n url: string;\n code?: number;\n message?: string;\n data?: string;\n}\n\n// This is set in _rs_init and needed for removal in _rs_cleanup\nlet onFeaturesLoaded: EventHandler;\n\nfunction extractParams (url?: string): AuthResult {\n // FF already decodes the URL fragment in document.location.hash, so use this instead:\n // eslint-disable-next-line\n const location = url || Authorize.getLocation().href;\n\n const queryParam = {};\n for (const [key, value] of new URL(location).searchParams) {\n queryParam[key] = value;\n }\n\n const hashPos = location.indexOf('#');\n if (hashPos === -1) { return queryParam; }\n const urlFragment = location.substring(hashPos+1);\n // if hash is not of the form #key=val&key=val, it's probably not for us\n if (!urlFragment.includes('=')) { return queryParam; }\n\n return urlFragment.split('&').reduce(function(params, kvs) {\n const kv = kvs.split('=');\n\n if (kv[0] === 'state' && kv[1].match(/rsDiscovery/)) {\n // extract rsDiscovery data from the state param\n let stateValue = decodeURIComponent(kv[1]);\n const encodedData = stateValue.substr(stateValue.indexOf('rsDiscovery='))\n .split('&')[0]\n .split('=')[1];\n\n params['rsDiscovery'] = JSON.parse(atob(encodedData));\n\n // remove rsDiscovery param\n stateValue = stateValue.replace(new RegExp('&?rsDiscovery=' + encodedData), '');\n\n if (stateValue.length > 0) {\n params['state'] = stateValue;\n }\n } else {\n params[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);\n }\n\n return params;\n }, queryParam);\n}\n\nfunction buildOAuthURL (options: AuthorizeOptions): string {\n const redirect = new URL(options.redirectUri);\n if (! options.state) {\n options.state = redirect.hash ? redirect.hash.substring(1) : '';\n }\n\n if (! options.response_type) {\n options.response_type = 'token';\n }\n\n const url = new URL(options.authURL);\n\n // We don't add a trailing slash as only pathname to redirectUri.\n url.searchParams.set('redirect_uri', options.redirectUri.replace(/#.*$/, ''));\n url.searchParams.set('scope', options.scope);\n url.searchParams.set('client_id', options.clientId);\n\n for (const key of ['state', 'response_type', 'code_challenge', 'code_challenge_method', 'token_access_type']) {\n const value = options[key];\n if (value) {\n url.searchParams.set(key, value);\n }\n }\n\n return url.href;\n}\n\nclass Authorize {\n static IMPLIED_FAKE_TOKEN = false;\n\n /**\n * Navigates browser to provider's OAuth page. When user grants access,\n * browser will navigate back to redirectUri and OAuth will continue\n * with onFeaturesLoaded.\n */\n static authorize (remoteStorage: RemoteStorage, options: AuthorizeOptions): void {\n log('[Authorize] authURL = ', options.authURL, 'scope = ', options.scope, 'redirectUri = ', options.redirectUri, 'clientId = ', options.clientId, 'response_type =', options.response_type );\n\n if (!options.scope) {\n throw new Error(\"Cannot authorize due to undefined or empty scope; did you forget to access.claim()?\");\n }\n\n // TODO add a test for this\n // keep track of the discovery data during redirect if we can't save it in localStorage\n if (!localStorageAvailable() && remoteStorage.backend === 'remotestorage') {\n options.redirectUri += options.redirectUri.indexOf('#') > 0 ? '&' : '#';\n\n const discoveryData = {\n userAddress: remoteStorage.remote.userAddress,\n href: remoteStorage.remote.href,\n storageApi: remoteStorage.remote.storageApi,\n properties: remoteStorage.remote.properties\n };\n\n options.redirectUri += 'rsDiscovery=' + toBase64(JSON.stringify(discoveryData));\n }\n\n const url = buildOAuthURL(options);\n\n // FIXME declare potential `cordova` property on global somehow, so we don't have to\n // use a string accessor here.\n if (globalContext['cordova']) {\n Authorize\n .openWindow(url, options.redirectUri, 'location=yes,clearsessioncache=yes,clearcache=yes')\n .then((authResult: AuthResult) => {\n remoteStorage.remote.configure({ token: authResult.access_token });\n });\n return;\n }\n\n Authorize.setLocation(url);\n }\n\n /** On success, calls remote.configure() with new access token */\n static async refreshAccessToken (rs: RemoteStorage, remote: Remote, refreshToken: string): Promise {\n await remote.configure({token: null, tokenType: null});\n const formValues = new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: remote.clientId,\n refresh_token: refreshToken,\n });\n const xhr = await requestWithTimeout('POST', remote.TOKEN_URL, {\n headers: {'Content-Type': 'application/x-www-form-urlencoded'},\n body: formValues.toString(),\n responseType: 'json'\n });\n if (xhr?.status === 200) {\n log(`[Authorize] access token good for ${xhr?.response?.expires_in} seconds`);\n const settings = {\n token: xhr?.response?.access_token,\n tokenType: xhr?.response?.token_type,\n };\n if (settings.token) {\n await remote.configure(settings);\n } else {\n throw new Error(`no access_token in \"successful\" refresh: ${xhr.response}`);\n }\n } else {\n await remote.configure({refreshToken: null});\n throw new UnauthorizedError(\"refresh token rejected:\" + JSON.stringify(xhr.response));\n }\n }\n\n /**\n * Get current document location\n *\n * Override this method if access to document.location is forbidden\n */\n static getLocation = function (): Location {\n return document.location;\n };\n\n /**\n * Open new InAppBrowser window for OAuth in Cordova\n */\n static openWindow = function (url: string, redirectUri: string, options: string): Promise {\n return new Promise((resolve, reject) => {\n\n const newWindow = open(url, '_blank', options);\n\n if (!newWindow || newWindow.closed) {\n reject('Authorization popup was blocked'); return;\n }\n\n function handleExit (): void {\n reject('Authorization was canceled');\n }\n\n function handleLoadstart (event: InAppBrowserEvent): void {\n if (event.url.indexOf(redirectUri) !== 0) { return; }\n\n newWindow.removeEventListener('exit', handleExit);\n newWindow.close();\n\n const authResult: AuthResult = extractParams(event.url);\n\n if (!authResult) {\n reject('Authorization error'); return;\n }\n\n resolve(authResult);\n }\n\n newWindow.addEventListener('loadstart', handleLoadstart);\n newWindow.addEventListener('exit', handleExit);\n });\n };\n\n /**\n * Set current document location\n *\n * Override this method if access to document.location is forbidden\n */\n static setLocation (location: string | Location): void {\n if (typeof location === 'string') {\n document.location.href = location;\n } else if (typeof location === 'object') {\n document.location = location;\n } else {\n throw \"Invalid location \" + location;\n }\n }\n\n static _rs_supported (): boolean {\n return typeof(document) !== 'undefined';\n }\n\n static _rs_init = function (remoteStorage: RemoteStorage): void {\n const params = extractParams();\n let location: Location;\n\n if (params) {\n location = Authorize.getLocation();\n location.hash = '';\n }\n\n // eslint-disable-next-line\n onFeaturesLoaded = function(): void {\n let authParamsUsed = false;\n\n if (!params) {\n remoteStorage.remote.stopWaitingForToken();\n return;\n }\n\n if (params.error) {\n if (params.error === 'access_denied') {\n throw new UnauthorizedError('Authorization failed: access denied', { code: 'access_denied' });\n } else {\n throw new UnauthorizedError(`Authorization failed: ${params.error}`);\n }\n }\n\n // rsDiscovery came with the redirect, because it couldn't be\n // saved in localStorage\n if (params.rsDiscovery) {\n remoteStorage.remote.configure(params.rsDiscovery);\n }\n\n if (params.access_token) {\n remoteStorage.remote.configure({ token: params.access_token });\n authParamsUsed = true;\n }\n\n if (params.remotestorage) {\n remoteStorage.connect(params.remotestorage);\n authParamsUsed = true;\n }\n\n if (params.state) {\n location = Authorize.getLocation();\n Authorize.setLocation(location.href.split('#')[0]+'#'+params.state);\n }\n\n if (params.code) { // OAuth2 code or PKCE flow\n fetchTokens(params.code); // remote.configure() called asynchronously\n authParamsUsed = true;\n }\n\n if (!authParamsUsed) {\n remoteStorage.remote.stopWaitingForToken();\n }\n };\n\n // OAuth2 PKCE flow\n async function fetchTokens(code: string) {\n const codeVerifier = sessionStorage.getItem('remotestorage:codeVerifier');\n if (!codeVerifier) {\n log(\"[Authorize] Ignoring OAuth code parameter, because no PKCE code verifier found in sessionStorage\");\n return;\n }\n location = Authorize.getLocation();\n let redirectUri = location.origin;\n if (location.pathname !== '/') {\n redirectUri += location.pathname;\n }\n const formValues = new URLSearchParams({\n code: code,\n grant_type: 'authorization_code',\n client_id: remoteStorage.remote.clientId,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier\n });\n const xhr = await requestWithTimeout(\n 'POST',\n remoteStorage.remote.TOKEN_URL,\n {\n headers: {'Content-Type': 'application/x-www-form-urlencoded'},\n body: formValues.toString(),\n responseType: 'json'\n }\n );\n\n switch (xhr.status) {\n case 200:\n log(`[Authorize] access token good for ${xhr?.response?.expires_in} seconds`);\n const settings = {\n token: xhr?.response?.access_token,\n refreshToken: xhr?.response?.refresh_token,\n tokenType: xhr?.response?.token_type,\n };\n if (settings.token) {\n remoteStorage.remote.configure(settings);\n } else {\n remoteStorage._emit('error', new Error(`no access_token in \"successful\" response: ${xhr.response}`));\n }\n sessionStorage.removeItem('remotestorage:codeVerifier');\n break;\n default:\n remoteStorage._emit('error', new Error(`${xhr.statusText}: ${xhr.response}`));\n }\n }\n\n remoteStorage.on('features-loaded', onFeaturesLoaded);\n };\n\n static _rs_cleanup (remoteStorage: RemoteStorage): void {\n remoteStorage.removeEventListener('features-loaded', onFeaturesLoaded);\n }\n}\n\nexport = Authorize;\n","class UnauthorizedError extends Error {\n code: string;\n\n constructor (message?: string, options: {code?: string} = {}) {\n super();\n this.name = 'Unauthorized';\n\n if (typeof message === 'undefined') {\n this.message = 'App authorization expired or revoked.';\n } else {\n this.message = message;\n }\n\n if (typeof options.code !== 'undefined') {\n this.code = options.code;\n }\n\n this.stack = (new Error()).stack;\n }\n}\n\nexport = UnauthorizedError;\n","var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n","/**\n * This file implements an HTTP request with timeout, on top of fetch or XHR.\n * The returned value always looks like an XHR.\n * It is used by authorize.ts, wireclient.ts, googledrive.ts and dropbox.ts.\n * The timeout is set by RemoteStorage#setRequestTimeout(timeout)\n */\n\nimport log from \"./log\";\nimport config from \"./config\";\n\n\n/**\n * Extracts a retry interval from header,\n * defaulting to three tries and a pause, within sync interval\n * */\nexport function retryAfterMs(xhr: XMLHttpRequest): number {\n const serverMs = parseInt(xhr.getResponseHeader('Retry-After')) * 1000;\n if (serverMs >= 1000) { // sanity check\n return serverMs;\n } else { // value is NaN if no such header, or malformed\n // three tries and a pause, within sync interval,\n // with lower & upper bounds\n return Math.max(1500, Math.min(60_000, Math.round(config.syncInterval / (2.9 + Math.random() * 0.2))));\n }\n}\n\nexport let isArrayBufferView: { (arg0: unknown): any; (object: any): boolean; (object: any): boolean };\n\nif (typeof ((global || window as any).ArrayBufferView) === 'function') {\n isArrayBufferView = function (object) {\n return object && (object instanceof (global || window as any).ArrayBufferView);\n };\n} else {\n const arrayBufferViews = [\n Int8Array, Uint8Array, Int16Array, Uint16Array,\n Int32Array, Uint32Array, Float32Array, Float64Array\n ];\n isArrayBufferView = function (object): boolean {\n for (let i = 0; i < 8; i++) {\n if (object instanceof arrayBufferViews[i]) {\n return true;\n }\n }\n return false;\n };\n}\n\n\nexport interface RequestOptions {\n body?: XMLHttpRequestBodyInit;\n headers?: HeadersInit;\n responseType?: XMLHttpRequestResponseType;\n}\n\nexport async function requestWithTimeout(method: string, url: string, options: RequestOptions): Promise {\n if (typeof fetch === 'function') {\n return _fetchRequestWithTimeout(method, url, options);\n } else if (typeof XMLHttpRequest === 'function') {\n return _xhrRequestWithTimeout(method, url, options);\n } else {\n return Promise.reject('[Requests] You need to add a polyfill for fetch or XMLHttpRequest');\n }\n}\n\nasync function _fetchRequestWithTimeout(method: string, url: string, options: RequestOptions): Promise {\n const abortController = typeof AbortController === 'function' ?\n new AbortController() :\n null;\n let timeoutId;\n\n const timeoutPromise: Promise = new Promise((_resolve, reject) => {\n timeoutId = setTimeout(() => {\n if (abortController) {\n abortController.abort();\n }\n reject('timeout');\n }, config.requestTimeout);\n });\n\n let syntheticXhr;\n const responseHeaders = {};\n\n const networkPromise: Promise = fetch(url, {\n method: method,\n headers: options.headers,\n body: options.body,\n signal: abortController ? abortController.signal : undefined\n }).then((response) => {\n log('[requests fetch]', response);\n\n response.headers.forEach((value: string, headerName: string) => {\n responseHeaders[headerName.toUpperCase()] = value;\n });\n\n syntheticXhr = {\n readyState: 4,\n status: response.status,\n statusText: response.statusText,\n response: undefined,\n getResponseHeader: (headerName: string): string => {\n return responseHeaders[headerName.toUpperCase()] || null;\n },\n // responseText: 'foo',\n responseType: options.responseType,\n responseURL: url,\n };\n switch (options.responseType) {\n case 'arraybuffer':\n return response.arrayBuffer();\n case 'blob':\n return response.blob();\n case 'json':\n return response.json();\n case undefined:\n case '':\n case 'text':\n return response.text();\n default: // document\n throw new Error(\"responseType 'document' is not currently supported using fetch\");\n }\n }).then((processedBody) => {\n syntheticXhr.response = processedBody;\n if (!options.responseType || options.responseType === 'text') {\n syntheticXhr.responseText = processedBody;\n }\n return syntheticXhr;\n }).finally(() => {\n clearTimeout(timeoutId);\n });\n\n return Promise.race([networkPromise, timeoutPromise]);\n}\n\nasync function _xhrRequestWithTimeout(method: string, url: string, options: RequestOptions): Promise {\n return new Promise((resolve, reject) => {\n\n log('[requests XHR]', method, url);\n\n let timedOut = false;\n\n const timer = setTimeout(() => {\n timedOut = true;\n reject('timeout');\n }, config.requestTimeout);\n\n const xhr = new XMLHttpRequest();\n xhr.open(method, url, true);\n\n if (options.responseType) {\n xhr.responseType = options.responseType;\n }\n\n if (options.headers) {\n for (const key in options.headers) {\n xhr.setRequestHeader(key, options.headers[key]);\n }\n }\n\n xhr.onload = (): void => {\n if (timedOut) {\n return;\n }\n clearTimeout(timer);\n resolve(xhr);\n };\n\n xhr.onerror = (error): void => {\n if (timedOut) {\n return;\n }\n clearTimeout(timer);\n reject(error);\n };\n\n let body = options.body;\n\n if (typeof (body) === 'object' && !isArrayBufferView(body) && body instanceof ArrayBuffer) {\n body = new Uint8Array(body);\n }\n xhr.send(body);\n });\n}\n","import tv4 from 'tv4';\nimport type { JsonSchemas } from './interfaces/json_schema';\nimport type { ChangeObj } from './interfaces/change_obj';\nimport type { QueuedRequestResponse } from './interfaces/queued_request_response';\nimport Types from './types';\nimport SchemaNotFound from './schema-not-found-error';\nimport EventHandling from './eventhandling';\nimport config from './config';\nimport { applyMixins, cleanPath, isFolder } from './util';\nimport RemoteStorage from './remotestorage';\n\nfunction getModuleNameFromBase(path: string): string {\n const parts = path.split('/');\n return path.length > 2 ? parts[1] : 'root';\n}\n\n/**\n * Provides a high-level interface to access data below a given root path.\n */\nclass BaseClient {\n /**\n * The instance this operates on.\n */\n storage: RemoteStorage;\n\n /**\n * Base path, which this operates on.\n *\n * For the module's privateClient this would be //, for the\n * corresponding publicClient /public//.\n */\n base: string;\n\n moduleName: string;\n\n constructor(storage: RemoteStorage, base: string) {\n if (base[base.length - 1] !== '/') {\n throw \"Not a folder: \" + base;\n }\n\n if (base === '/') {\n // allow absolute and relative paths for the root scope.\n this.makePath = (path: string): string => {\n return (path[0] === '/' ? '' : '/') + path;\n };\n }\n\n this.storage = storage;\n this.base = base;\n this.moduleName = getModuleNameFromBase(this.base);\n\n this.addEvents(['change']);\n this.on = this.on.bind(this);\n storage.onChange(this.base, this._fireChange.bind(this));\n }\n\n /**\n * Instantiate a new client, scoped to a subpath of the current client's\n * path.\n *\n * @param path - The path to scope the new client to\n *\n * @returns A new client operating on a subpath of the current base path\n */\n scope (path: string): BaseClient {\n return new BaseClient(this.storage, this.makePath(path));\n }\n\n /**\n * Get a list of child nodes below a given path.\n *\n * @param {string} path - The path to query. It MUST end with a forward slash.\n * @param {number} maxAge - (optional) Either ``false`` or the maximum age of\n * cached listing in milliseconds. See :ref:`max-age`.\n *\n * @returns {Promise} A promise for an object representing child nodes\n */\n // TODO add real return type\n async getListing (path?: string, maxAge?: false | number): Promise {\n if (typeof path !== 'string') { path = ''; }\n else if (path.length > 0 && !isFolder(path)) {\n return Promise.reject(\"Not a folder: \" + path);\n }\n\n return this.storage.get(this.makePath(path), maxAge).then((r: QueuedRequestResponse) => {\n return r.statusCode === 404 ? {} : r.body;\n });\n }\n\n /**\n * Get all objects directly below a given path.\n *\n * @param {string} path - Path to the folder. Must end in a forward slash.\n * @param {number} maxAge - (optional) Either ``false`` or the maximum age of\n * cached objects in milliseconds. See :ref:`max-age`.\n *\n * @returns {Promise} A promise for an object\n */\n // TODO add real return type\n async getAll (path: string, maxAge?: false | number): Promise {\n if (typeof path !== 'string') { path = ''; }\n else if (path.length > 0 && !isFolder(path)) {\n return Promise.reject(\"Not a folder: \" + path);\n }\n\n return this.storage.get(this.makePath(path), maxAge).then((r: QueuedRequestResponse) => {\n if (r.statusCode === 404) { return {}; }\n if (typeof r.body === 'object') {\n const keys = Object.keys(r.body);\n // treat this like 404. it probably means a folder listing that\n // has changes that haven't been pushed out yet.\n if (keys.length === 0) { return {}; }\n\n const calls = keys.map((key: string) => {\n return this.storage.get(this.makePath(path + key), maxAge)\n .then((o: QueuedRequestResponse) => {\n if (typeof o.body === 'string') {\n try { o.body = JSON.parse(o.body); }\n catch (e) { /* empty */ }\n }\n if (typeof o.body === 'object') {\n r.body[key] = o.body;\n }\n });\n });\n\n return Promise.all(calls).then(() => { return r.body; });\n }\n });\n }\n\n /**\n * Get the file at the given path. A file is raw data, as opposed to\n * a JSON object (use :func:`getObject` for that).\n *\n * @param {string} path - Relative path from the module root (without leading\n * slash).\n * @param {number} maxAge - (optional) Either ``false`` or the maximum age of\n * the cached file in milliseconds. See :ref:`max-age`.\n *\n * @returns {Promise} A promise for an object\n */\n // TODO add real return type\n async getFile (path: string, maxAge?: false | number): Promise {\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.getFile must be a string');\n }\n\n return this.storage.get(this.makePath(path), maxAge).then((r: QueuedRequestResponse) => {\n return {\n data: r.body,\n contentType: r.contentType,\n revision: r.revision // (this is new)\n };\n });\n }\n\n /**\n * Store raw data at a given path.\n *\n * @param {string} mimeType - MIME media type of the data being stored\n * @param {string} path - Path relative to the module root\n * @param {string|ArrayBuffer|ArrayBufferView} body - Raw data to store\n *\n * @returns {Promise} A promise for the created/updated revision (ETag)\n */\n async storeFile (mimeType: string, path: string, body: string | ArrayBuffer | ArrayBufferView): Promise {\n if (typeof mimeType !== 'string') {\n return Promise.reject('Argument \\'mimeType\\' of baseClient.storeFile must be a string');\n }\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.storeFile must be a string');\n }\n if ((typeof body !== 'string') && (typeof body !== 'object')) {\n return Promise.reject('Argument \\'body\\' of baseClient.storeFile must be a string, ArrayBuffer, or ArrayBufferView');\n }\n if (!this.storage.access.checkPathPermission(this.makePath(path), 'rw')) {\n console.warn('WARNING: Editing a document to which only read access (\\'r\\') was claimed');\n }\n\n return this.storage.put(this.makePath(path), body, mimeType).then((r: QueuedRequestResponse) => {\n if (r.statusCode === 200 || r.statusCode === 201) {\n return r.revision;\n } else {\n return Promise.reject(\"Request (PUT \" + this.makePath(path) + \") failed with status: \" + r.statusCode);\n }\n });\n }\n\n /**\n * Get a JSON object from the given path.\n *\n * @param {string} path - Relative path from the module root (without leading\n * slash).\n * @param {number} maxAge - (optional) Either ``false`` or the maximum age of\n * cached object in milliseconds. See :ref:`max-age`.\n *\n * @returns {Promise} A promise, which resolves with the requested object (or ``null``\n * if non-existent)\n */\n\n // TODO add real return type\n async getObject (path: string, maxAge?: false | number): Promise {\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.getObject must be a string');\n }\n\n return this.storage.get(this.makePath(path), maxAge).then((r: QueuedRequestResponse) => {\n if (typeof r.body === 'object') { // will be the case for documents stored with rs.js <= 0.10.0-beta2\n return r.body;\n } else if (typeof r.body === 'string') {\n try {\n return JSON.parse(r.body);\n } catch (e) {\n throw new Error(\"Not valid JSON: \" + this.makePath(path));\n }\n } else if (typeof r.body !== 'undefined' && r.statusCode === 200) {\n return Promise.reject(\"Not an object: \" + this.makePath(path));\n }\n });\n }\n\n /**\n * Store object at given path. Triggers synchronization.\n *\n * See ``declareType()`` and :doc:`data types `\n * for an explanation of types\n *\n * For any given `path`, must not be called more frequently than once per second.\n *\n * @param {string} typeAlias - Unique type of this object within this module.\n * @param {string} path - Path relative to the module root.\n * @param {object} object - A JavaScript object to be stored at the given\n * path. Must be serializable as JSON.\n *\n * @returns {Promise} Resolves with revision on success. Rejects with\n * a ValidationError, if validations fail.\n */\n // TODO add real return type\n async storeObject (typeAlias: string, path: string, object: object): Promise {\n if (typeof typeAlias !== 'string') {\n return Promise.reject('Argument \\'typeAlias\\' of baseClient.storeObject must be a string');\n }\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.storeObject must be a string');\n }\n if (typeof object !== 'object') {\n return Promise.reject('Argument \\'object\\' of baseClient.storeObject must be an object');\n }\n\n this._attachType(object, typeAlias);\n\n try {\n const validationResult = this.validate(object);\n if (!validationResult.valid) {\n return Promise.reject(validationResult);\n }\n } catch (exc) {\n return Promise.reject(exc);\n }\n\n return this.storage.put(this.makePath(path), JSON.stringify(object), 'application/json; charset=UTF-8').then((r: QueuedRequestResponse) => {\n if (r.statusCode === 200 || r.statusCode === 201) {\n return r.revision;\n } else {\n return Promise.reject(\"Request (PUT \" + this.makePath(path) + \") failed with status: \" + r.statusCode);\n }\n });\n }\n\n /**\n * Remove node at given path from storage. Triggers synchronization.\n *\n * @param {string} path - Path relative to the module root.\n * @returns {Promise}\n */\n // TODO add real return type\n remove (path: string): Promise {\n if (typeof path !== 'string') {\n return Promise.reject('Argument \\'path\\' of baseClient.remove must be a string');\n }\n if (!this.storage.access.checkPathPermission(this.makePath(path), 'rw')) {\n console.warn('WARNING: Removing a document to which only read access (\\'r\\') was claimed');\n }\n\n return this.storage.delete(this.makePath(path));\n }\n\n /**\n * Retrieve full URL of a document. Useful for example for sharing the public\n * URL of an item in the ``/public`` folder.\n * TODO: refactor this into the Remote interface\n *\n * @param {string} path - Path relative to the module root.\n * @returns {string} The full URL of the item, including the storage origin\n */\n getItemURL (path: string): string {\n if (typeof path !== 'string') {\n throw 'Argument \\'path\\' of baseClient.getItemURL must be a string';\n }\n if (this.storage.connected) {\n path = cleanPath(this.makePath(path));\n return this.storage.remote.href + path;\n } else {\n return undefined;\n }\n }\n\n /**\n * Set caching strategy for a given path and its children.\n *\n * See :ref:`caching-strategies` for a detailed description of the available\n * strategies.\n *\n * @param {string} path - Path to cache\n * @param {string} strategy - Caching strategy. One of 'ALL', 'SEEN', or\n * 'FLUSH'. Defaults to 'ALL'.\n *\n * @returns {BaseClient} The same instance this is called on to allow for method chaining\n */\n cache (path: string, strategy: 'ALL' | 'SEEN' | 'FLUSH' = 'ALL'): BaseClient {\n if (typeof path !== 'string') {\n throw 'Argument \\'path\\' of baseClient.cache must be a string';\n }\n if (typeof strategy !== 'string') {\n throw 'Argument \\'strategy\\' of baseClient.cache must be a string or undefined';\n }\n if (strategy !== 'FLUSH' &&\n strategy !== 'SEEN' &&\n strategy !== 'ALL') {\n throw 'Argument \\'strategy\\' of baseclient.cache must be one of '\n + '[\"FLUSH\", \"SEEN\", \"ALL\"]';\n }\n\n this.storage.caching.set(this.makePath(path), strategy);\n return this;\n }\n\n /**\n * TODO: document\n *\n * @param {string} path\n */\n // TODO add return type once known\n flush (path: string): unknown {\n return this.storage.local.flush(path);\n }\n\n /**\n * Declare a remoteStorage object type using a JSON schema.\n *\n * See :doc:`Defining data types ` for more info.\n *\n * @param {string} alias - A type alias/shortname\n * @param {uri} uri - (optional) JSON-LD URI of the schema. Automatically generated if none given\n * @param {object} schema - A JSON Schema object describing the object type\n **/\n declareType (alias: string, uriOrSchema: string|tv4.JsonSchema, schema?: tv4.JsonSchema): void {\n let uri: string;\n\n if (schema && typeof uriOrSchema === 'string') {\n uri = uriOrSchema;\n } else if (!schema && typeof uriOrSchema !== 'string') {\n schema = uriOrSchema;\n uri = this._defaultTypeURI(alias);\n } else if (!schema && typeof uriOrSchema === 'string') {\n throw new Error('declareType() requires a JSON Schema object to be passed, in order to validate object types/formats');\n }\n\n BaseClient.Types.declare(this.moduleName, alias, uri, schema);\n }\n\n /**\n * Validate an object against the associated schema.\n *\n * @param {Object} object - JS object to validate. Must have a ``@context`` property.\n *\n * @returns {Object} An object containing information about validation errors\n **/\n validate (object: {[key: string]: any}): {[key: string]: any} {\n const schema = BaseClient.Types.getSchema(object['@context']);\n if (schema) {\n return tv4.validateResult(object, schema);\n } else {\n throw new SchemaNotFound(object['@context']);\n }\n }\n\n /**\n * TODO document\n *\n * @private\n */\n schemas = {\n configurable: true,\n\n get (): JsonSchemas {\n return BaseClient.Types.inScope(this.moduleName);\n }\n };\n\n /**\n * The default JSON-LD @context URL for RS types/objects/documents\n *\n * @private\n */\n _defaultTypeURI (alias: string): string {\n return 'http://remotestorage.io/spec/modules/' + encodeURIComponent(this.moduleName) + '/' + encodeURIComponent(alias);\n }\n\n /**\n * Attaches the JSON-LD @content to an object\n *\n * @private\n */\n _attachType (object: object, alias: string): void {\n object['@context'] = BaseClient.Types.resolveAlias(this.moduleName + '/' + alias) || this._defaultTypeURI(alias);\n }\n\n /**\n * TODO: document\n *\n * @private\n */\n makePath (path: string): string {\n return this.base + (path || '');\n }\n\n /**\n * TODO: document\n *\n * @private\n */\n _fireChange (event: ChangeObj): void {\n if (config.changeEvents[event.origin]) {\n ['new', 'old', 'lastCommon'].forEach(function (fieldNamePrefix) {\n if ((!event[fieldNamePrefix + 'ContentType'])\n || (/^application\\/(.*)json(.*)/.exec(event[fieldNamePrefix + 'ContentType']))) {\n if (typeof event[fieldNamePrefix + 'Value'] === 'string') {\n try {\n event[fieldNamePrefix + 'Value'] = JSON.parse(event[fieldNamePrefix + 'Value']);\n } catch (e) {\n // empty\n }\n }\n }\n });\n this._emit('change', event);\n }\n }\n\n static Types = Types;\n\n static _rs_init (): void {\n return;\n }\n}\n\ninterface BaseClient extends EventHandling {}\napplyMixins(BaseClient, [EventHandling]);\n\nexport = BaseClient;\n","import RemoteStorage from \"./remotestorage\";\nimport EventHandling from \"./eventhandling\";\nimport {isFolder} from \"./util\";\n\n/**\n * The ancestor for WireClient, GoogleDrive & Dropbox\n */\nexport class RemoteBase extends EventHandling {\n rs: RemoteStorage;\n\n connected: boolean;\n online: boolean;\n userAddress: string;\n storageApi: string;\n\n constructor(rs: RemoteStorage) {\n super();\n this.rs = rs;\n this.connected = false;\n // TODO: Should `online` be set true or false for all, here or in configure?\n }\n\n stopWaitingForToken (): void {\n if (!this.connected) {\n this._emit('not-connected');\n }\n }\n\n addQuotes (str: string): string {\n if (typeof (str) !== 'string') {\n return str;\n }\n if (str === '*') {\n return '*';\n }\n\n return '\"' + str + '\"';\n }\n\n stripQuotes (str: string): string {\n if (typeof (str) !== 'string') {\n return str;\n }\n\n return str.replace(/^[\"']|[\"']$/g, '');\n }\n\n isForbiddenRequestMethod(method: string, uri: string): boolean {\n if (method === 'PUT' || method === 'DELETE') {\n return isFolder(uri);\n } else {\n return false;\n }\n }\n}\n\n\nexport interface RemoteSettings {\n userAddress?: string;\n href?: string; // remoteStorage server's base URL\n storageApi?: string; // spec version\n token?: string | false; // OAuth2 access token\n refreshToken?: string; // OAuth2 refresh token\n tokenType?: string; // type of access token; usually 'bearer'\n properties?: object;\n}\n\nexport interface RemoteResponse {\n statusCode: number;\n revision?: string;\n contentType?: string;\n body?: any;\n}\n\n/**\n * The public interface for WireClient, GoogleDrive & Dropbox\n */\nexport interface Remote {\n connected: boolean;\n online: boolean;\n userAddress: string;\n\n /**\n * Holds the spec version the server claims to be compatible with\n *\n * Example:\n * (start code)\n *\n * remoteStorage.remote.storageApi\n * // -> 'draft-dejong-remotestorage-01'\n */\n storageApi: string;\n\n /**\n * Holds the server's base URL, as obtained in the Webfinger discovery\n *\n * Example:\n * (start code)\n *\n * remoteStorage.remote.href\n * // -> 'https://storage.example.com/users/jblogg/'\n */\n href?: string;\n\n /** the JSON-parsed properties object from the user's WebFinger record */\n properties?: object;\n\n clientId?: string; // OAuth2\n TOKEN_URL?: string; // OAuth2 PKCE\n\n configure (settings): void // TODO: harmonize settings & use type\n\n configure (settings: RemoteSettings): void;\n\n /**\n * Initiate the authorization flow's OAuth dance.\n */\n connect? (): void;\n\n stopWaitingForToken (): void;\n\n get (path: string, options: { ifMatch?: string; ifNoneMatch?: string }): Promise;\n\n put (path: string, body: XMLHttpRequestBodyInit, contentType: string, options: { ifMatch?: string; ifNoneMatch?: string }): Promise\n\n delete (path: string, options: { ifMatch?: string }): Promise;\n}\n","class SyncError extends Error {\n originalError: Error;\n\n constructor (originalError: string | Error) {\n super();\n this.name = 'SyncError';\n this.message = 'Sync failed: ';\n if (typeof originalError === 'string') {\n this.message += originalError;\n } else {\n this.message += originalError.message;\n this.stack = originalError.stack;\n this.originalError = originalError;\n }\n }\n}\n\nexport = SyncError;\n","import type { ChangeObj } from './interfaces/change_obj';\nimport type { QueuedRequestResponse } from './interfaces/queued_request_response';\nimport type { RSEvent } from './interfaces/rs_event';\nimport type { RSNode, RSNodes, ProcessNodes } from './interfaces/rs_node';\nimport EventHandling from './eventhandling';\nimport config from './config';\nimport log from './log';\nimport {\n applyMixins,\n deepClone,\n equal,\n isDocument,\n isFolder,\n pathsFromRoot\n} from './util';\n\nfunction getLatest (node: RSNode): any {\n if (typeof (node) !== 'object' || typeof (node.path) !== 'string') {\n return;\n }\n if (isFolder(node.path)) {\n if (node.local && node.local.itemsMap) {\n return node.local;\n }\n if (node.common && node.common.itemsMap) {\n return node.common;\n }\n } else {\n if (node.local) {\n if (node.local.body && node.local.contentType) {\n return node.local;\n }\n if (node.local.body === false) {\n return;\n }\n }\n if (node.common && node.common.body && node.common.contentType) {\n return node.common;\n }\n // Migration code! Once all apps use at least this version of the lib, we\n // can publish clean-up code that migrates over any old-format data, and\n // stop supporting it. For now, new apps will support data in both\n // formats, thanks to this:\n if (node.body && node.contentType) {\n return {\n body: node.body,\n contentType: node.contentType\n };\n }\n }\n}\n\nfunction isOutdated (nodes: RSNodes, maxAge: number): boolean {\n for (const path in nodes) {\n if (nodes[path] && nodes[path].remote) {\n return true;\n }\n const nodeVersion = getLatest(nodes[path]);\n if (nodeVersion && nodeVersion.timestamp && (new Date().getTime()) - nodeVersion.timestamp <= maxAge) {\n return false;\n } else if (!nodeVersion) {\n return true;\n }\n }\n return true;\n}\n\n\nfunction makeNode (path: string): RSNode {\n const node: RSNode = {path: path, common: {}};\n\n if (isFolder(path)) {\n node.common.itemsMap = {};\n }\n return node;\n}\n\nfunction updateFolderNodeWithItemName (node: RSNode, itemName: string): RSNode {\n if (!node.common) {\n node.common = {\n itemsMap: {}\n };\n }\n if (!node.common.itemsMap) {\n node.common.itemsMap = {};\n }\n if (!node.local) {\n node.local = deepClone(node.common);\n }\n if (!node.local.itemsMap) {\n node.local.itemsMap = node.common.itemsMap;\n }\n node.local.itemsMap[itemName] = true;\n\n return node;\n}\n\n/**\n * This module defines functions that are mixed into remoteStorage.local when\n * it is instantiated (currently one of indexeddb.js, localstorage.js, or\n * inmemorystorage.js).\n *\n * All remoteStorage.local implementations should therefore implement\n * this.getNodes, this.setNodes, and this.forAllNodes. The rest is blended in\n * here to create a GPD (get/put/delete) interface which the BaseClient can\n * talk to.\n *\n * @interface\n */\n\nabstract class CachingLayer {\n // FIXME\n // this process of updating nodes needs to be heavily documented first, then\n // refactored. Right now it's almost impossible to refactor as there's no\n // explanation of why things are implemented certain ways or what the goal(s)\n // of the behavior are. -slvrbckt (+1 -les)\n private _updateNodesRunning = false;\n private _updateNodesQueued = [];\n\n\n // functions that will be overwritten\n // ----------------------------------\n abstract getNodes(paths: string[]): Promise;\n\n abstract diffHandler(...args: any[]);\n\n abstract forAllNodes(cb: (node) => any): Promise;\n\n abstract setNodes(nodes: RSNodes): Promise;\n\n\n // --------------------------------------------------\n\n // TODO: improve our code structure so that this function\n // could call sync.queueGetRequest directly instead of needing\n // this hacky third parameter as a callback\n async get (path: string, maxAge: number, queueGetRequest: (path2: string) => Promise): Promise {\n\n if (typeof (maxAge) === 'number') {\n return this.getNodes(pathsFromRoot(path))\n .then((objs) => {\n const node: RSNode = getLatest(objs[path]);\n\n if (isOutdated(objs, maxAge)) {\n return queueGetRequest(path);\n } else if (node) {\n return {\n statusCode: 200,\n body: node.body || node.itemsMap,\n contentType: node.contentType\n };\n } else {\n return { statusCode: 404 };\n }\n });\n } else {\n return this.getNodes([path])\n .then((objs) => {\n const node: RSNode = getLatest(objs[path]);\n\n if (node) {\n if (isFolder(path)) {\n for (const i in node.itemsMap) {\n // the hasOwnProperty check here is only because our jshint settings require it:\n if (node.itemsMap.hasOwnProperty(i) && node.itemsMap[i] === false) {\n delete node.itemsMap[i];\n }\n }\n }\n return {\n statusCode: 200,\n body: node.body || node.itemsMap,\n contentType: node.contentType\n };\n } else {\n return {statusCode: 404};\n }\n });\n }\n }\n\n async put (path: string, body: unknown, contentType: string): Promise {\n const paths = pathsFromRoot(path);\n\n function _processNodes(nodePaths: string[], nodes: RSNodes): RSNodes {\n try {\n for (let i = 0, len = nodePaths.length; i < len; i++) {\n const nodePath = nodePaths[i];\n let node = nodes[nodePath];\n let previous: RSNode;\n\n if (!node) {\n nodes[nodePath] = node = makeNode(nodePath);\n }\n\n // Document\n if (i === 0) {\n previous = getLatest(node);\n node.local = {\n body: body,\n contentType: contentType,\n previousBody: (previous ? previous.body : undefined),\n previousContentType: (previous ? previous.contentType : undefined),\n };\n }\n // Folder\n else {\n const itemName = nodePaths[i - 1].substring(nodePath.length);\n node = updateFolderNodeWithItemName(node, itemName);\n }\n }\n return nodes;\n } catch (e) {\n log('[Cachinglayer] Error during PUT', nodes, e);\n throw e;\n }\n }\n\n return this._updateNodes(paths, _processNodes);\n }\n\n delete (path: string): unknown {\n const paths = pathsFromRoot(path);\n\n return this._updateNodes(paths, function (nodePaths, nodes) {\n for (let i = 0, len = nodePaths.length; i < len; i++) {\n const nodePath = nodePaths[i];\n const node = nodes[nodePath];\n let previous;\n\n if (!node) {\n console.error('Cannot delete non-existing node ' + nodePath);\n continue;\n }\n\n if (i === 0) {\n // Document\n previous = getLatest(node);\n node.local = {\n body: false,\n previousBody: (previous ? previous.body : undefined),\n previousContentType: (previous ? previous.contentType : undefined),\n };\n } else {\n // Folder\n if (!node.local) {\n node.local = deepClone(node.common);\n }\n const itemName = nodePaths[i - 1].substring(nodePath.length);\n delete node.local.itemsMap[itemName];\n\n if (Object.getOwnPropertyNames(node.local.itemsMap).length > 0) {\n // This folder still contains other items, don't remove any further ancestors\n break;\n }\n }\n }\n return nodes;\n });\n }\n\n flush(path: string): unknown {\n\n return this._getAllDescendentPaths(path).then((paths: string[]) => {\n return this.getNodes(paths);\n }).then((nodes: RSNodes) => {\n for (const nodePath in nodes) {\n const node = nodes[nodePath];\n\n if (node && node.common && node.local) {\n this._emitChange({\n path: node.path,\n origin: 'local',\n oldValue: (node.local.body === false ? undefined : node.local.body),\n newValue: (node.common.body === false ? undefined : node.common.body)\n });\n }\n nodes[nodePath] = undefined;\n }\n\n return this.setNodes(nodes);\n });\n }\n\n private _emitChange(obj: ChangeObj): void {\n if (config.changeEvents[obj.origin]) {\n this._emit('change', obj);\n }\n }\n\n fireInitial (): void {\n if (!config.changeEvents.local) { return; }\n\n this.forAllNodes((node) => {\n if (isDocument(node.path)) {\n const latest = getLatest(node);\n if (latest) {\n this._emitChange({\n path: node.path,\n origin: 'local',\n oldValue: undefined,\n oldContentType: undefined,\n newValue: latest.body,\n newContentType: latest.contentType\n });\n }\n }\n }).then(() => {\n this._emit('local-events-done');\n });\n }\n\n // TODO add proper type\n onDiff(diffHandler: any) {\n this.diffHandler = diffHandler;\n }\n\n migrate(node: RSNode): RSNode {\n if (typeof (node) === 'object' && !node.common) {\n node.common = {};\n if (typeof (node.path) === 'string') {\n if (node.path.substr(-1) === '/' && typeof (node.body) === 'object') {\n node.common.itemsMap = node.body;\n }\n } else {\n //save legacy content of document node as local version\n if (!node.local) {\n node.local = {};\n }\n node.local.body = node.body;\n node.local.contentType = node.contentType;\n }\n }\n return node;\n }\n\n\n private _updateNodes(paths: string[], _processNodes: ProcessNodes): Promise {\n return new Promise((resolve, reject) => {\n this._doUpdateNodes(paths, _processNodes, {\n resolve: resolve,\n reject: reject\n });\n });\n }\n\n private _doUpdateNodes(paths: string[], _processNodes: ProcessNodes, promise) {\n if (this._updateNodesRunning) {\n this._updateNodesQueued.push({\n paths: paths,\n cb: _processNodes,\n promise: promise\n });\n return;\n } else {\n this._updateNodesRunning = true;\n }\n\n this.getNodes(paths).then((nodes) => {\n const existingNodes = deepClone(nodes);\n const changeEvents = [];\n\n nodes = _processNodes(paths, nodes);\n\n for (const path in nodes) {\n const node = nodes[path];\n if (equal(node, existingNodes[path])) {\n delete nodes[path];\n } else if (isDocument(path)) {\n if (\n !equal(node.local.body, node.local.previousBody) ||\n node.local.contentType !== node.local.previousContentType\n ) {\n changeEvents.push({\n path: path,\n origin: 'window',\n oldValue: node.local.previousBody,\n newValue: node.local.body === false ? undefined : node.local.body,\n oldContentType: node.local.previousContentType,\n newContentType: node.local.contentType\n });\n }\n delete node.local.previousBody;\n delete node.local.previousContentType;\n }\n }\n\n this.setNodes(nodes).then(() => {\n this._emitChangeEvents(changeEvents);\n promise.resolve({statusCode: 200});\n });\n }).then(() => {\n return Promise.resolve();\n }, (err) => {\n promise.reject(err);\n }).then(() => {\n this._updateNodesRunning = false;\n const nextJob = this._updateNodesQueued.shift();\n if (nextJob) {\n this._doUpdateNodes(nextJob.paths, nextJob.cb, nextJob.promise);\n }\n });\n }\n\n private _emitChangeEvents(events: RSEvent[]) {\n for (let i = 0, len = events.length; i < len; i++) {\n this._emitChange(events[i]);\n if (this.diffHandler) {\n this.diffHandler(events[i].path);\n }\n }\n }\n\n private _getAllDescendentPaths(path: string) {\n if (isFolder(path)) {\n return this.getNodes([path]).then((nodes) => {\n const allPaths = [path];\n const latest = getLatest(nodes[path]);\n\n const itemNames = Object.keys(latest.itemsMap);\n const calls = itemNames.map((itemName) => {\n return this._getAllDescendentPaths(path + itemName).then((paths) => {\n for (let i = 0, len = paths.length; i < len; i++) {\n allPaths.push(paths[i]);\n }\n });\n });\n return Promise.all(calls).then(() => {\n return allPaths;\n });\n });\n } else {\n return Promise.resolve([path]);\n }\n }\n\n // treated as private but made public for unit testing\n _getInternals() {\n return {\n getLatest: getLatest,\n makeNode: makeNode,\n isOutdated: isOutdated\n };\n }\n}\n\n\ninterface CachingLayer extends EventHandling {}\napplyMixins(CachingLayer, [EventHandling]);\n\nexport = CachingLayer;\n","// TODO maybe move to common interfaces & types file\n// also worth considering enums\ntype AccessMode = 'r' | 'rw';\ntype AccessScope = string;\n\ninterface ScopeEntry {\n name: string;\n mode: AccessMode;\n}\n\ninterface ScopeModeMap {\n // NOTE: key is actually AccessScope\n [key: string]: AccessMode;\n}\n\n/**\n * @class Access\n *\n * Keeps track of claimed access and scopes.\n */\nclass Access {\n scopeModeMap: ScopeModeMap;\n rootPaths: string[];\n storageType: string;\n\n // TODO create custom type for init function\n static _rs_init(): void {\n return;\n }\n\n constructor() {\n this.reset();\n }\n\n /**\n * Property: scopes\n *\n * Holds an array of claimed scopes in the form\n * > { name: \"\", mode: \"\" }\n */\n get scopes(): ScopeEntry[] {\n return Object.keys(this.scopeModeMap).map((key) => {\n return { name: key, mode: this.scopeModeMap[key] };\n });\n }\n\n get scopeParameter(): string {\n return this.scopes.map((scope) => {\n return `${this._scopeNameForParameter(scope)}:${scope.mode}`;\n }).join(' ');\n }\n\n /**\n * Claim access on a given scope with given mode.\n *\n * @param {string} scope - An access scope, such as \"contacts\" or \"calendar\"\n * @param {string} mode - Access mode. Either \"r\" for read-only or \"rw\" for read/write\n */\n claim (scope: AccessScope, mode: AccessMode): void {\n if (typeof (scope) !== 'string' || scope.indexOf('/') !== -1 || scope.length === 0) {\n throw new Error('Scope should be a non-empty string without forward slashes');\n }\n if (!mode.match(/^rw?$/)) {\n throw new Error('Mode should be either \\'r\\' or \\'rw\\'');\n }\n this._adjustRootPaths(scope);\n this.scopeModeMap[scope] = mode;\n }\n\n /**\n * Get the access mode for a given scope.\n *\n * @param {string} scope - Access scope\n * @returns {string} Access mode\n */\n get (scope: AccessScope): AccessMode {\n return this.scopeModeMap[scope];\n }\n\n\n /**\n * Remove access for the given scope.\n *\n * @param {string} scope - Access scope\n */\n remove (scope: AccessScope): void {\n const savedMap: ScopeModeMap = {};\n for (const name in this.scopeModeMap) {\n savedMap[name] = this.scopeModeMap[name];\n }\n this.reset();\n delete savedMap[scope];\n for (const name in savedMap) {\n this.claim(name as AccessScope, savedMap[name]);\n }\n }\n\n /**\n * Verify permission for a given scope.\n *\n * @param {string} scope - Access scope\n * @param {string} mode - Access mode\n * @returns {boolean} true if the requested access mode is active, false otherwise\n */\n checkPermission (scope: AccessScope, mode: AccessMode): boolean {\n const actualMode = this.get(scope);\n return actualMode && (mode === 'r' || actualMode === 'rw');\n }\n\n /**\n * Verify permission for a given path.\n *\n * @param {string} path - Path\n * @param {string} mode - Access mode\n * @returns {boolean} true if the requested access mode is active, false otherwise\n */\n checkPathPermission (path: string, mode: AccessMode): boolean {\n if (this.checkPermission('*', mode)) {\n return true;\n }\n // TODO check if this is reliable\n const scope = this._getModuleName(path) as AccessScope;\n return !!this.checkPermission(scope, mode);\n }\n\n /**\n * Reset all access permissions.\n */\n reset(): void {\n this.rootPaths = [];\n this.scopeModeMap = {};\n }\n\n /**\n * Return the module name for a given path.\n */\n private _getModuleName (path): string {\n if (path[0] !== '/') {\n throw new Error('Path should start with a slash');\n }\n const moduleMatch = path.replace(/^\\/public/, '').match(/^\\/([^/]*)\\//);\n return moduleMatch ? moduleMatch[1] : '*';\n }\n\n /**\n * TODO: document\n */\n private _adjustRootPaths (newScope: AccessScope): void {\n if ('*' in this.scopeModeMap || newScope === '*') {\n this.rootPaths = ['/'];\n } else if (!(newScope in this.scopeModeMap)) {\n this.rootPaths.push('/' + newScope + '/');\n this.rootPaths.push('/public/' + newScope + '/');\n }\n }\n\n /**\n * TODO: document\n */\n private _scopeNameForParameter (scope: ScopeEntry): string {\n if (scope.name === '*' && this.storageType) {\n if (this.storageType === '2012.04') {\n return '';\n } else if (this.storageType.match(/remotestorage-0[01]/)) {\n return 'root';\n }\n }\n return scope.name;\n }\n\n /**\n * Set the storage type of the remote.\n *\n * @param {string} type - Storage type\n */\n setStorageType (type: string): void {\n this.storageType = type;\n }\n}\n\nexport = Access;\n","import { containingFolder, isFolder } from './util';\nimport log from './log';\n\n/**\n * @class Caching\n *\n * Holds/manages caching configuration.\n **/\nclass Caching {\n pendingActivations: string[] = [];\n // TODO add correct type\n activateHandler: (firstPending: string) => void;\n\n private _rootPaths: object;\n\n constructor () {\n this.reset();\n }\n\n /**\n * Configure caching for a given path explicitly.\n *\n * Not needed when using ``enable``/``disable``.\n *\n * @param {string} path - Path to cache\n * @param {string} strategy - Caching strategy. One of 'ALL', 'SEEN', or 'FLUSH'.\n */\n set (path: string, strategy: 'ALL' | 'SEEN' | 'FLUSH'): void {\n if (typeof path !== 'string') {\n throw new Error('path should be a string');\n }\n if (!isFolder(path)) {\n throw new Error('path should be a folder');\n }\n // FIXME We need to get to the access instance somehow. But I'm not sure\n // this check is even necessary in the first place. -raucao\n // if (!this._remoteStorage.access.checkPathPermission(path, 'r')) {\n // throw new Error('No access to path \"' + path + '\". You have to claim access to it first.');\n // }\n if (!strategy.match(/^(FLUSH|SEEN|ALL)$/)) {\n throw new Error(\"strategy should be 'FLUSH', 'SEEN', or 'ALL'\");\n }\n\n this._rootPaths[path] = strategy;\n\n if (strategy === 'ALL') {\n if (this.activateHandler) {\n this.activateHandler(path);\n } else {\n this.pendingActivations.push(path);\n }\n }\n }\n\n /**\n * Enable caching for a given path.\n *\n * Uses caching strategy ``ALL``.\n *\n * @param {string} path - Path to enable caching for\n */\n enable (path: string): void {\n this.set(path, 'ALL');\n }\n\n /**\n * Disable caching for a given path.\n *\n * Uses caching strategy ``FLUSH`` (meaning items are only cached until\n * successfully pushed to the remote).\n *\n * @param {string} path - Path to disable caching for\n */\n disable (path: string): void {\n this.set(path, 'FLUSH');\n }\n\n /**\n * Set a callback for when caching is activated for a path.\n *\n * @param {function} cb - Callback function\n */\n onActivate (cb: (firstPending: string) => void): void {\n log('[Caching] Setting activate handler', cb, this.pendingActivations);\n this.activateHandler = cb;\n for (let i = 0; i < this.pendingActivations.length; i++) {\n cb(this.pendingActivations[i]);\n }\n this.pendingActivations = [];\n }\n\n /**\n * Retrieve caching setting for a given path, or its next parent\n * with a caching strategy set.\n *\n * @param {string} path - Path to retrieve setting for\n * @returns {string} caching strategy for the path\n **/\n checkPath (path: string): string {\n if (this._rootPaths[path] !== undefined) {\n return this._rootPaths[path];\n } else if (path === '/') {\n return 'SEEN';\n } else {\n return this.checkPath(containingFolder(path));\n }\n }\n\n /**\n * Reset the state of caching by deleting all caching information.\n **/\n reset (): void {\n this._rootPaths = {};\n }\n\n /**\n * Setup function that is called on initialization.\n *\n * @private\n **/\n static _rs_init (/*remoteStorage*/): void {\n return;\n }\n}\n\nexport = Caching;\n","import BaseClient from './baseclient';\nimport EventHandling from './eventhandling';\nimport {\n applyMixins,\n isFolder,\n cleanPath,\n shouldBeTreatedAsBinary,\n getJSONFromLocalStorage,\n getTextFromArrayBuffer,\n localStorageAvailable\n} from './util';\nimport {requestWithTimeout, RequestOptions} from \"./requests\";\nimport {Remote, RemoteBase, RemoteResponse, RemoteSettings} from \"./remote\";\n\nconst BASE_URL = 'https://www.googleapis.com';\nconst AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';\nconst AUTH_SCOPE = 'https://www.googleapis.com/auth/drive';\nconst SETTINGS_KEY = 'remotestorage:googledrive';\nconst PATH_PREFIX = '/remotestorage';\n\nconst GD_DIR_MIME_TYPE = 'application/vnd.google-apps.folder';\nconst RS_DIR_MIME_TYPE = 'application/json; charset=UTF-8';\n\nlet hasLocalStorage;\n\n/**\n * Produce a title from a filename for metadata.\n *\n * @param {string} filename\n * @returns {string} title\n *\n * @private\n */\nfunction metaTitleFromFileName (filename: string): string {\n if (filename.substr(-1) === '/') {\n filename = filename.substr(0, filename.length - 1);\n }\n\n return decodeURIComponent(filename);\n}\n\n/**\n * Get the parent directory for the given path.\n *\n * @param {string} path\n * @returns {string} parent directory\n *\n * @private\n */\nfunction parentPath (path: string): string {\n return path.replace(/[^\\/]+\\/?$/, '');\n}\n\n/**\n * Get only the filename from a full path.\n *\n * @param {string} path\n * @returns {string} filename\n *\n * @private\n */\nfunction baseName (path: string): string {\n const parts = path.split('/');\n if (path.substr(-1) === '/') {\n return parts[parts.length-2]+'/';\n } else {\n return parts[parts.length-1];\n }\n}\n\n/**\n * Prepend the path with the remoteStorage base directory.\n *\n * @param {string} path - Path\n * @returns {string} Actual path on Google Drive\n *\n * @private\n */\nfunction googleDrivePath (path: string): string {\n return cleanPath(`${PATH_PREFIX}/${path}`);\n}\n\n/**\n * Internal cache object for storing Google file IDs.\n *\n * @param {number} maxAge - Maximum age (in seconds) the content should be cached for\n */\nclass FileIdCache {\n maxAge: number;\n _items = {};\n\n constructor(maxAge?: number) {\n this.maxAge = maxAge;\n this._items = {};\n }\n\n get (key): number | undefined {\n const item = this._items[key];\n const now = new Date().getTime();\n return (item && item.t >= (now - this.maxAge)) ? item.v : undefined;\n }\n\n set (key, value): void {\n this._items[key] = {\n v: value,\n t: new Date().getTime()\n };\n }\n}\n\n/**\n * Overwrite BaseClient's getItemURL with our own implementation\n *\n * TODO: Still needs to be implemented. At the moment it just throws\n * and error saying that it's not implemented yet.\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @private\n */\nfunction hookGetItemURL (rs): void {\n if (rs._origBaseClientGetItemURL) { return; }\n rs._origBaseClientGetItemURL = BaseClient.prototype.getItemURL;\n BaseClient.prototype.getItemURL = function (/* path */): never {\n throw new Error('getItemURL is not implemented for Google Drive yet');\n };\n}\n\n/**\n * Restore BaseClient's getItemURL original implementation\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @private\n */\nfunction unHookGetItemURL (rs): void {\n if (!rs._origBaseClientGetItemURL) { return; }\n BaseClient.prototype.getItemURL = rs._origBaseClientGetItemURL;\n delete rs._origBaseClientGetItemURL;\n}\n\n/**\n * @class GoogleDrive\n *\n * To use this backend, you need to specify the app's client ID like so:\n *\n * @example\n * remoteStorage.setApiKeys({\n * googledrive: 'your-client-id'\n * });\n *\n * A client ID can be obtained by registering your app in the Google\n * Developers Console: https://console.developers.google.com/flows/enableapi?apiid=drive\n *\n * Docs: https://developers.google.com/drive/v3/web/quickstart/js\n**/\nclass GoogleDrive extends RemoteBase implements Remote {\n clientId: string;\n token: string;\n\n _fileIdCache: FileIdCache;\n\n constructor(remoteStorage, clientId) {\n super(remoteStorage);\n this.online = true;\n this.storageApi = 'draft-dejong-remotestorage-19';\n this.addEvents(['connected', 'not-connected']);\n\n this.clientId = clientId;\n\n this._fileIdCache = new FileIdCache(60 * 5); // IDs expire after 5 minutes (is this a good idea?)\n\n hasLocalStorage = localStorageAvailable();\n\n if (hasLocalStorage){\n const settings = getJSONFromLocalStorage(SETTINGS_KEY);\n if (settings) {\n this.configure(settings);\n }\n }\n }\n\n /**\n * Configure the Google Drive backend.\n *\n * Fetches the user info from Google when no ``userAddress`` is given.\n *\n * @param {Object} settings\n * @param {string} [settings.userAddress] - The user's email address\n * @param {string} [settings.token] - Authorization token\n *\n * @protected\n */\n configure (settings: RemoteSettings) { // Settings parameter compatible with WireClient\n // We only update this.userAddress if settings.userAddress is set to a string or to null\n if (typeof settings.userAddress !== 'undefined') { this.userAddress = settings.userAddress; }\n // Same for this.token. If only one of these two is set, we leave the other one at its existing value\n if (typeof settings.token !== 'undefined') { this.token = settings.token as string; }\n\n const writeSettingsToCache = function() {\n if (hasLocalStorage) {\n localStorage.setItem(SETTINGS_KEY, JSON.stringify({\n userAddress: this.userAddress,\n token: this.token\n }));\n }\n };\n\n const handleError = function() {\n this.connected = false;\n delete this.token;\n if (hasLocalStorage) {\n localStorage.removeItem(SETTINGS_KEY);\n }\n };\n\n if (this.token) {\n this.connected = true;\n\n if (this.userAddress) {\n this._emit('connected');\n writeSettingsToCache.apply(this);\n } else {\n this.info().then((info) => {\n this.userAddress = info.user.emailAddress;\n this._emit('connected');\n writeSettingsToCache.apply(this);\n }).catch(() => {\n handleError.apply(this);\n this.rs._emit('error', new Error('Could not fetch user info.'));\n });\n }\n } else {\n handleError.apply(this);\n }\n }\n\n /**\n * Initiate the authorization flow's OAuth dance.\n */\n connect (): void {\n this.rs.setBackend('googledrive');\n this.rs.authorize({ authURL: AUTH_URL, scope: AUTH_SCOPE, clientId: this.clientId });\n }\n\n /**\n * Request a resource (file or directory).\n *\n * @param {string} path - Path of the resource\n * @param {Object} options - Request options\n * @returns {Promise} Resolves with an object containing the status code,\n * body, content-type and revision\n *\n * @protected\n */\n get (path: string, options: { ifNoneMatch?: string } = {}): Promise {\n if (isFolder(path)) {\n return this._getFolder(googleDrivePath(path));\n } else {\n return this._getFile(googleDrivePath(path), options);\n }\n }\n\n /**\n * Create or update a file.\n *\n * @param {string} path - File path\n * @param body - File content\n * @param {string} contentType - File content-type\n * @param {Object} options\n * @param {string} options.ifNoneMatch - Only create of update the file if the\n * current ETag doesn't match this string\n * @returns {Promise} Resolves with an object containing the status code,\n * content-type and revision\n *\n * @protected\n */\n put (path: string, body: XMLHttpRequestBodyInit, contentType: string, options: { ifMatch?: string; ifNoneMatch?: string } = {}): Promise {\n const fullPath = googleDrivePath(path);\n\n function putDone(response) {\n if (response.status >= 200 && response.status < 300) {\n const meta = JSON.parse(response.responseText);\n const etagWithoutQuotes: string = this.stripQuotes(meta.etag);\n return Promise.resolve({statusCode: 200, contentType: meta.mimeType, revision: etagWithoutQuotes});\n } else if (response.status === 412) {\n return Promise.resolve({statusCode: 412, revision: 'conflict'});\n } else {\n return Promise.reject(\"PUT failed with status \" + response.status + \" (\" + response.responseText + \")\");\n }\n }\n\n return this._getFileId(fullPath).then((id) => {\n if (id) {\n if (options && (options.ifNoneMatch === '*')) {\n return putDone({ status: 412 });\n }\n return this._updateFile(id, fullPath, body, contentType, options).then(putDone);\n } else {\n return this._createFile(fullPath, body, contentType).then(putDone);\n }\n });\n }\n\n /**\n * Delete a file.\n *\n * @param {string} path - File path\n * @param {Object} options\n * @param {string} options.ifMatch - only delete the file if it's ETag\n * matches this string\n * @returns {Promise} Resolves with an object containing the status code\n *\n * @protected\n */\n delete (path: string, options: { ifMatch?: string } = {}): Promise {\n const fullPath = googleDrivePath(path);\n\n return this._getFileId(fullPath).then((id) => {\n if (!id) {\n // File doesn't exist. Ignore.\n return Promise.resolve({statusCode: 200});\n }\n\n return this._getMeta(id).then((meta) => {\n let etagWithoutQuotes;\n if ((typeof meta === 'object') && (typeof meta.etag === 'string')) {\n etagWithoutQuotes = this.stripQuotes(meta.etag);\n }\n if (options && options.ifMatch && (options.ifMatch !== etagWithoutQuotes)) {\n return {statusCode: 412, revision: etagWithoutQuotes};\n }\n\n return this._request('DELETE', BASE_URL + '/drive/v2/files/' + id, {}).then((response) => {\n if (response.status === 200 || response.status === 204) {\n return {statusCode: 200};\n } else {\n return Promise.reject(\"Delete failed: \" + response.status + \" (\" + response.responseText + \")\");\n }\n });\n });\n });\n }\n\n /**\n * Fetch the user's info from Google.\n *\n * @returns {Promise} resolves with the user's info.\n *\n * @protected\n */\n info () {\n const url = BASE_URL + '/drive/v2/about?fields=user';\n // requesting user info(mainly for userAdress)\n return this._request('GET', url, {}).then(function (resp){\n try {\n const info = JSON.parse(resp.responseText);\n return Promise.resolve(info);\n } catch (e) {\n return Promise.reject(e);\n }\n });\n }\n\n /**\n * Update an existing file.\n *\n * @param {string} id - File ID\n * @param {string} path - File path\n * @param body - File content\n * @param {string} contentType - File content-type\n * @param {Object} options\n * @param {string} options.ifMatch - Only update the file if its ETag\n * matches this string\n * @returns {Promise} Resolves with the response of the network request\n *\n * @private\n */\n _updateFile (id, path, body, contentType, options) {\n const metadata = {\n mimeType: contentType\n };\n const headers = {\n 'Content-Type': 'application/json; charset=UTF-8'\n };\n\n if (options && options.ifMatch) {\n headers['If-Match'] = this.addQuotes(options.ifMatch);\n }\n\n return this._request('PUT', BASE_URL + '/upload/drive/v2/files/' + id + '?uploadType=resumable', {\n body: JSON.stringify(metadata),\n headers: headers\n }).then((response) => {\n if (response.status === 412) {\n return (response);\n } else {\n return this._request('PUT', response.getResponseHeader('Location'), {\n body: contentType.match(/^application\\/json/) ? JSON.stringify(body) : body\n });\n }\n });\n }\n\n /**\n * Create a new file.\n *\n * @param {string} path - File path\n * @param body - File content\n * @param {string} contentType - File content-type\n * @returns {Promise} Resolves with the response of the network request\n *\n * @private\n */\n _createFile (path, body, contentType) {\n return this._getParentId(path).then((parentId) => {\n const fileName = baseName(path);\n const metadata = {\n title: metaTitleFromFileName(fileName),\n mimeType: contentType,\n parents: [{\n kind: \"drive#fileLink\",\n id: parentId\n }]\n };\n return this._request('POST', BASE_URL + '/upload/drive/v2/files?uploadType=resumable', {\n body: JSON.stringify(metadata),\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8'\n }\n }).then((response) => {\n return this._request('POST', response.getResponseHeader('Location'), {\n body: contentType.match(/^application\\/json/) ? JSON.stringify(body) : body\n });\n });\n });\n }\n\n /**\n * Request a file.\n *\n * @param {string} path - File path\n * @param {Object} options\n * @param {string} [options.ifNoneMath] - Only return the file if its ETag\n * doesn't match the given string\n * @returns {Promise} Resolves with an object containing the status code,\n * body, content-type and revision\n *\n * @private\n */\n _getFile (path, options) {\n return this._getFileId(path).then((id) => {\n return this._getMeta(id).then((meta) => {\n let etagWithoutQuotes;\n if (typeof(meta) === 'object' && typeof(meta.etag) === 'string') {\n etagWithoutQuotes = this.stripQuotes(meta.etag);\n }\n\n if (options && options.ifNoneMatch && (etagWithoutQuotes === options.ifNoneMatch)) {\n return Promise.resolve({statusCode: 304});\n }\n\n if (!meta.downloadUrl) {\n if (meta.exportLinks && meta.exportLinks['text/html']) {\n // Documents that were generated inside GoogleDocs have no\n // downloadUrl, but you can export them to text/html instead:\n meta.mimeType += ';export=text/html';\n meta.downloadUrl = meta.exportLinks['text/html'];\n } else {\n // empty file\n return Promise.resolve({statusCode: 200, body: '', contentType: meta.mimeType, revision: etagWithoutQuotes});\n }\n }\n\n const params: RequestOptions = {\n responseType: 'arraybuffer'\n };\n return this._request('GET', meta.downloadUrl, params).then((response) => {\n //first encode the response as text, and later check if\n //text appears to actually be binary data\n return getTextFromArrayBuffer(response.response, 'UTF-8').then(function (responseText) {\n let body = responseText;\n if (meta.mimeType.match(/^application\\/json/)) {\n try {\n body = JSON.parse(body as string);\n } catch(e) {\n // body couldn't be parsed as JSON, so we'll just return it as is\n }\n } else if (shouldBeTreatedAsBinary(responseText, meta.mimeType)) {\n //return unprocessed response\n body = response.response;\n }\n\n return {\n statusCode: 200,\n body: body,\n contentType: meta.mimeType,\n revision: etagWithoutQuotes\n };\n });\n });\n });\n });\n }\n\n /**\n * Request a directory.\n *\n * @param {string} path - Directory path\n * @returns {Promise} Resolves with an object containing the status code,\n * body and content-type\n *\n * @private\n */\n _getFolder (path: string) {\n return this._getFileId(path).then((id) => {\n let data, etagWithoutQuotes, itemsMap;\n if (! id) {\n return Promise.resolve({statusCode: 404});\n }\n\n const query = '\\'' + id + '\\' in parents';\n const fields = 'items(downloadUrl,etag,fileSize,id,mimeType,title,labels)';\n return this._request('GET', BASE_URL + '/drive/v2/files?'\n + 'q=' + encodeURIComponent(query)\n + '&fields=' + encodeURIComponent(fields)\n + '&maxResults=1000'\n + '&trashed=false',\n {})\n .then((response) => {\n if (response.status !== 200) {\n return Promise.reject('request failed or something: ' + response.status);\n }\n\n try {\n data = JSON.parse(response.responseText);\n } catch(e) {\n return Promise.reject('non-JSON response from GoogleDrive');\n }\n\n itemsMap = {};\n for (const item of data.items) {\n if (item.labels?.trashed) { continue; } // ignore deleted files\n\n etagWithoutQuotes = this.stripQuotes(item.etag);\n if (item.mimeType === GD_DIR_MIME_TYPE) {\n this._fileIdCache.set(path + cleanPath(item.title) + '/', item.id);\n itemsMap[item.title + '/'] = {\n ETag: etagWithoutQuotes\n };\n } else {\n this._fileIdCache.set(path + cleanPath(item.title), item.id);\n itemsMap[item.title] = {\n ETag: etagWithoutQuotes,\n 'Content-Type': item.mimeType,\n 'Content-Length': item.fileSize\n };\n }\n }\n\n // FIXME: add revision of folder!\n return Promise.resolve({statusCode: 200, body: itemsMap, contentType: RS_DIR_MIME_TYPE, revision: undefined});\n });\n });\n }\n\n /**\n * Get the ID of a parent path.\n *\n * Creates the directory if it doesn't exist yet.\n *\n * @param {string} path - Full path of a directory or file\n * @returns {Promise} Resolves with ID of the parent directory.\n *\n * @private\n */\n _getParentId (path) {\n const foldername = parentPath(path);\n\n return this._getFileId(foldername).then((parentId) => {\n if (parentId) {\n return Promise.resolve(parentId);\n } else {\n return this._createFolder(foldername);\n }\n });\n }\n\n /**\n * Create a directory.\n *\n * Creates all parent directories as well if any of them didn't exist yet.\n *\n * @param {string} path - Directory path\n * @returns {Promise} Resolves with the ID of the new directory\n *\n * @private\n */\n _createFolder (path) {\n return this._getParentId(path).then((parentId) => {\n return this._request('POST', BASE_URL + '/drive/v2/files', {\n body: JSON.stringify({\n title: metaTitleFromFileName(baseName(path)),\n mimeType: GD_DIR_MIME_TYPE,\n parents: [{\n id: parentId\n }]\n }),\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8'\n }\n }).then((response) => {\n const meta = JSON.parse(response.responseText);\n return Promise.resolve(meta.id);\n });\n });\n }\n\n /**\n * Get the ID of a file.\n *\n * @param {string} path - File path\n * @returns {Promise} Resolves with the ID\n *\n * @private\n */\n _getFileId (path) {\n let id;\n\n if (path === '/') {\n // \"root\" is a special alias for the fileId of the root folder\n return Promise.resolve('root');\n } else if ((id = this._fileIdCache.get(path))) {\n // id is cached.\n return Promise.resolve(id);\n }\n // id is not cached (or file doesn't exist).\n // load parent folder listing to propagate / update id cache.\n return this._getFolder(parentPath(path)).then(() => {\n id = this._fileIdCache.get(path);\n if (!id) {\n if (path.substr(-1) === '/') {\n return this._createFolder(path).then(() => {\n return this._getFileId(path);\n });\n } else {\n return Promise.resolve();\n }\n }\n return Promise.resolve(id);\n });\n }\n\n /**\n * Get the metadata for a given file ID.\n *\n * @param {string} id - File ID\n * @returns {Promise} Resolves with an object containing the metadata\n *\n * @private\n */\n _getMeta (id) {\n return this._request('GET', BASE_URL + '/drive/v2/files/' + id, {}).then(function (response) {\n if (response.status === 200) {\n return Promise.resolve(JSON.parse(response.responseText));\n } else {\n return Promise.reject(\"request (getting metadata for \" + id + \") failed with status: \" + response.status);\n }\n });\n }\n\n /**\n * Make a network request.\n *\n * @param {string} method - Request method\n * @param {string} url - Target URL\n * @param {Object} options - Request options\n * @returns {Promise} Resolves with the response of the network request\n *\n * @private\n */\n _request (method: string, url: string, options: RequestOptions) {\n if (this.isForbiddenRequestMethod(method, url)) {\n return Promise.reject(`Don't use ${method} on directories!`);\n }\n\n if (! options.headers) { options.headers = {}; }\n options.headers['Authorization'] = 'Bearer ' + this.token;\n\n this.rs._emit('wire-busy', {\n method: method,\n isFolder: isFolder(url)\n });\n\n return requestWithTimeout(method, url, options).then((xhr) => {\n // Google tokens expire from time to time...\n if (xhr && xhr.status === 401) {\n this.connect();\n return;\n } else {\n if (!this.online) {\n this.online = true;\n this.rs._emit('network-online');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(url),\n success: true\n });\n\n return Promise.resolve(xhr);\n }\n }, (error) => {\n if (this.online) {\n this.online = false;\n this.rs._emit('network-offline');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(url),\n success: false\n });\n\n return Promise.reject(error);\n });\n }\n\n /**\n * Initialize the Google Drive backend.\n *\n * @param {Object} remoteStorage - RemoteStorage instance\n *\n * @protected\n */\n static _rs_init (remoteStorage): void {\n const config = remoteStorage.apiKeys.googledrive;\n if (config) {\n remoteStorage.googledrive = new GoogleDrive(remoteStorage, config.clientId);\n if (remoteStorage.backend === 'googledrive') {\n remoteStorage._origRemote = remoteStorage.remote;\n remoteStorage.remote = remoteStorage.googledrive;\n\n hookGetItemURL(remoteStorage);\n }\n }\n }\n\n /**\n * Inform about the availability of the Google Drive backend.\n *\n * @returns {Boolean}\n *\n * @protected\n */\n static _rs_supported (): boolean {\n return true;\n }\n\n /**\n * Remove Google Drive as a backend.\n *\n * @param {Object} remoteStorage - RemoteStorage instance\n *\n * @protected\n */\n static _rs_cleanup (remoteStorage): void {\n remoteStorage.setBackend(undefined);\n if (remoteStorage._origRemote) {\n remoteStorage.remote = remoteStorage._origRemote;\n delete remoteStorage._origRemote;\n }\n unHookGetItemURL(remoteStorage);\n }\n}\n\ninterface GoogleDrive extends EventHandling {}\napplyMixins(GoogleDrive, [EventHandling]);\n\nexport = GoogleDrive;\n","import EventHandling from './eventhandling';\nimport BaseClient from './baseclient';\nimport RevisionCache from './revisioncache';\nimport SyncError from './sync-error';\nimport UnauthorizedError from './unauthorized-error';\nimport {\n applyMixins,\n isFolder,\n shouldBeTreatedAsBinary,\n getJSONFromLocalStorage,\n getTextFromArrayBuffer,\n localStorageAvailable,\n generateCodeVerifier,\n} from './util';\nimport {requestWithTimeout, isArrayBufferView, retryAfterMs} from \"./requests\";\nimport {Remote, RemoteBase, RemoteResponse, RemoteSettings} from \"./remote\";\nimport RemoteStorage from \"./remotestorage\";\nimport Authorize from \"./authorize\";\n\n/**\n * WORK IN PROGRESS, NOT RECOMMENDED FOR PRODUCTION USE\n *\n * Dropbox backend for RemoteStorage.js\n * This file exposes a get/put/delete interface which is compatible with\n * .\n *\n * When remoteStorage.backend is set to 'dropbox', this backend will\n * initialize and replace remoteStorage.remote with remoteStorage.dropbox.\n *\n * In order to ensure compatibility with the public folder, \n * gets hijacked to return the Dropbox public share URL.\n *\n * To use this backend, you need to specify the Dropbox app key like so:\n *\n * @example\n * remoteStorage.setApiKeys({\n * dropbox: 'your-app-key'\n * });\n *\n * An app key can be obtained by registering your app at https://www.dropbox.com/developers/apps\n *\n * Known issues:\n *\n * - Storing files larger than 150MB is not yet supported\n * - Listing and deleting folders with more than 10'000 files will cause problems\n * - Content-Type is not supported; TODO: use file_properties\n * - Dropbox preserves cases but is not case-sensitive\n * - getItemURL is asynchronous which means it returns useful values\n * after the syncCycle\n */\n\nlet hasLocalStorage;\nconst AUTH_URL = 'https://www.dropbox.com/oauth2/authorize';\nconst ACCOUNT_URL = 'https://api.dropboxapi.com/2/users/get_current_account';\nconst TOKEN_URL = 'https://api.dropboxapi.com/oauth2/token';\nconst OAUTH_SCOPE = 'account_info.read files.content.read files.content.write files.metadata.read files.metadata.write';\nconst SETTINGS_KEY = 'remotestorage:dropbox';\nconst FOLDER_URL = 'https://api.dropboxapi.com/2/files/list_folder';\nconst CONTINUE_URL = 'https://api.dropboxapi.com/2/files/list_folder/continue';\nconst DOWNLOAD_URL = 'https://content.dropboxapi.com/2/files/download';\nconst UPLOAD_URL = 'https://content.dropboxapi.com/2/files/upload';\nconst DELETE_URL = 'https://api.dropboxapi.com/2/files/delete';\nconst METADATA_URL = 'https://api.dropboxapi.com/2/files/get_metadata';\nconst CREATE_SHARED_URL = 'https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings';\nconst LIST_SHARED_URL = 'https://api.dropbox.com/2/sharing/list_shared_links';\nconst PATH_PREFIX = '/remotestorage';\nconst NUM_RETRIES = 3;\n\ninterface Metadata {\n \".tag\": \"folder\" | \"file\";\n id: string;\n name: string;\n path_display: string;\n path_lower: string;\n property_groups: any[];\n sharing_info: {\n no_access?: boolean;\n parent_shared_folder_id: string;\n read_only: boolean;\n traverse_only?: boolean;\n modified_by?: string;\n };\n\n client_modified?: string; // date\n content_hash?: string;\n file_lock_info?: {\n created: string; // date\n is_lockholder: boolean;\n lockholder_name: string;\n };\n has_explicit_shared_members?: boolean;\n is_downloadable?: boolean;\n rev?: string;\n server_modified?: string; // date\n size?: number;\n\n preview_url?: string;\n}\n\n/**\n * Maps a remoteStorage path to a path in Dropbox.\n *\n * @param {string} path - Path\n * @returns {string} Actual path in Dropbox\n *\n * @private\n */\nfunction getDropboxPath (path: string): string {\n return (PATH_PREFIX + '/' + path).replace(/\\/+$/, '').replace(/\\/+/g, '/');\n}\n\n// This function is simple and has OK performance compared to more\n// complicated ones: https://jsperf.com/json-escape-unicode/4\nconst charsToEncode = /[\\u007f-\\uffff]/g;\nfunction httpHeaderSafeJson(obj) {\n return JSON.stringify(obj).replace(charsToEncode,\n function(c) {\n return '\\\\u'+('000'+c.charCodeAt(0).toString(16)).slice(-4);\n }\n );\n}\n\nfunction compareApiError (response: {error_summary: string}, expect: string[]): boolean {\n return new RegExp('^' + expect.join('\\\\/') + '(\\\\/|$)').test(response.error_summary);\n}\n\nfunction isBinaryData (data): boolean {\n return data instanceof ArrayBuffer || isArrayBufferView(data);\n}\n\n/**\n * @class\n */\nclass Dropbox extends RemoteBase implements Remote {\n clientId: string;\n TOKEN_URL: string; // OAuth2 PKCE\n token: string;\n refreshToken: string; // OAuth2 PKCE\n tokenType: string; // OAuth2 PKCE\n userAddress: string;\n\n _initialFetchDone: boolean;\n _revCache: RevisionCache;\n _fetchDeltaCursor: string;\n _fetchDeltaPromise: Promise;\n _itemRefs: { [key: string]: string };\n\n // TODO remove when refactoring eventhandling\n _emit: any;\n\n constructor (rs) {\n super(rs);\n this.online = true; // TODO implement offline detection on failed request\n this.storageApi = 'draft-dejong-remotestorage-19';\n this._initialFetchDone = false;\n\n this.addEvents(['connected', 'not-connected']);\n\n this.clientId = rs.apiKeys.dropbox.appKey;\n this.TOKEN_URL = TOKEN_URL;\n this._revCache = new RevisionCache('rev');\n this._fetchDeltaCursor = null;\n this._fetchDeltaPromise = null;\n this._itemRefs = {};\n\n hasLocalStorage = localStorageAvailable();\n\n if (hasLocalStorage){\n const settings = getJSONFromLocalStorage(SETTINGS_KEY);\n if (settings) {\n this.configure(settings); // can't await in constructor\n }\n this._itemRefs = getJSONFromLocalStorage(`${SETTINGS_KEY}:shares`) || {};\n }\n if (this.connected) {\n setTimeout(this._emit.bind(this), 0, 'connected');\n }\n }\n\n /**\n * Set the backed to 'dropbox' and start the authentication flow in order\n * to obtain an API token from Dropbox.\n */\n async connect () {\n // TODO handling when token is already present\n try {\n this.rs.setBackend('dropbox');\n if (this.token) {\n hookIt(this.rs);\n } else { // OAuth2 PKCE\n const {codeVerifier, codeChallenge, state} = await generateCodeVerifier();\n sessionStorage.setItem('remotestorage:codeVerifier', codeVerifier);\n sessionStorage.setItem('remotestorage:state', state);\n this.rs.authorize({\n authURL: AUTH_URL,\n scope: OAUTH_SCOPE,\n clientId: this.clientId,\n response_type: 'code',\n state: state,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n token_access_type: 'offline'\n });\n }\n } catch (err) {\n this.rs._emit('error', err);\n this.rs.setBackend(undefined);\n throw err;\n }\n }\n\n /**\n * Sets the connected flag\n * Accepts its parameters according to the .\n * @param {Object} settings\n * @param {string} [settings.userAddress] - The user's email address\n * @param {string} [settings.token] - Authorization token\n * @param {string} [settings.refreshToken] - OAuth2 PKCE refresh token\n * @param {string} [settings.tokenType] - usually 'bearer' - no support for 'mac' tokens yet\n *\n * @protected\n **/\n async configure (settings: RemoteSettings): Promise {\n // We only update this.userAddress if settings.userAddress is set to a string or to null:\n if (typeof settings.userAddress !== 'undefined') { this.userAddress = settings.userAddress; }\n // Same for this.token. If only one of these two is set, we leave the other one at its existing value:\n if (typeof settings.token !== 'undefined') { this.token = settings.token as string; }\n if (typeof settings.refreshToken !== 'undefined') { this.refreshToken = settings.refreshToken; }\n if (typeof settings.tokenType !== 'undefined') { this.tokenType = settings.tokenType; }\n\n const writeSettingsToCache = () => {\n if (hasLocalStorage) {\n localStorage.setItem(SETTINGS_KEY, JSON.stringify({\n userAddress: this.userAddress,\n token: this.token,\n refreshToken: this.refreshToken,\n tokenType: this.tokenType,\n }));\n }\n };\n\n const handleError = () => {\n this.connected = false;\n if (hasLocalStorage) {\n localStorage.removeItem(SETTINGS_KEY);\n }\n this.rs.setBackend(undefined);\n };\n\n if (this.refreshToken || this.token) {\n this.connected = true;\n if (this.userAddress) {\n this._emit('connected');\n writeSettingsToCache();\n } else {\n try {\n const info = await this.info();\n this.userAddress = info.email;\n this._emit('connected');\n writeSettingsToCache();\n } catch (err) {\n this.connected = false;\n this.rs._emit('error', new Error('Could not fetch user info.'));\n writeSettingsToCache.apply(this);\n }\n }\n } else {\n handleError();\n }\n }\n\n /**\n * Get all items in a folder.\n *\n * @param path {string} - path of the folder to get, with leading slash\n * @return {Object}\n * statusCode - HTTP status code\n * body - array of the items found\n * contentType - 'application/json; charset=UTF-8'\n * revision - revision of the folder\n *\n * @private\n */\n _getFolder (path: string) {\n const revCache = this._revCache;\n\n const processResponse = (resp) => {\n let body;\n\n if (resp.status !== 200 && resp.status !== 409) {\n return Promise.reject('Unexpected response status: ' + resp.status);\n }\n\n try {\n body = JSON.parse(resp.responseText);\n } catch (e) {\n return Promise.reject(e);\n }\n\n if (resp.status === 409) {\n if (compareApiError(body, ['path', 'not_found'])) {\n // if the folder is not found, handle it as an empty folder\n return Promise.resolve({});\n }\n\n return Promise.reject(new Error('API returned an error: ' + body.error_summary));\n }\n\n const listing = body.entries.reduce((map, item) => {\n try {\n const isDir = item['.tag'] === 'folder';\n const itemName = item.path_display.split('/').slice(-1)[0] + (isDir ? '/' : '');\n if (isDir) {\n map[itemName] = {ETag: revCache.get(path + itemName)};\n } else {\n const date = new Date(item.server_modified);\n map[itemName] = {ETag: item.rev, 'Content-Length': item.size, 'Last-Modified': date.toUTCString()};\n this._revCache.set(path + itemName, item.rev);\n }\n } catch (err) {\n console.error(`[Dropbox] folder “${path}” has entry ${JSON.stringify(item)}:`, err);\n }\n return map;\n }, {});\n\n if (body.has_more) {\n return loadNext(body.cursor).then(function (nextListing) {\n return Object.assign(listing, nextListing);\n });\n }\n\n return Promise.resolve(listing);\n };\n\n const loadNext = (cursor) => {\n const params = {\n body: { cursor: cursor }\n };\n\n return this._request('POST', CONTINUE_URL, params).then(processResponse);\n };\n\n return this._request('POST', FOLDER_URL, {\n body: {\n path: getDropboxPath(path)\n }\n }).then(processResponse).then(function (listing) {\n return Promise.resolve({\n statusCode: 200,\n body: listing,\n contentType: 'application/json; charset=UTF-8',\n revision: revCache.get(path)\n });\n });\n }\n\n /**\n * Checks for the path in ``_revCache`` and decides based on that if file\n * has changed. Calls ``_getFolder`` is the path points to a folder.\n *\n * Calls ``Dropbox.share`` afterwards to fill ``_itemRefs``.\n *\n * Compatible with ``WireClient.get``\n *\n * @param path {string} - path of the folder to get, with leading slash\n * @param options {Object}\n *\n * @protected\n */\n get (path: string, options: { ifNoneMatch?: string } = {}): Promise {\n if (! this.connected) { return Promise.reject(\"not connected (path: \" + path + \")\"); }\n const savedRev = this._revCache.get(path);\n if (savedRev === null) {\n // file was deleted server side\n return Promise.resolve({statusCode: 404});\n }\n if (options && options.ifNoneMatch) {\n // We must wait for local revision cache to be initialized before\n // checking if local revision is outdated\n if (! this._initialFetchDone) {\n return this.fetchDelta().then(() => {\n return this.get(path, options);\n });\n }\n\n if (savedRev && (savedRev === options.ifNoneMatch)) {\n // nothing changed.\n return Promise.resolve({statusCode: 304});\n }\n }\n\n // use _getFolder for folders\n if (path.slice(-1) === '/') {\n return this._getFolder(path);\n }\n\n const params = {\n headers: {\n 'Dropbox-API-Arg': httpHeaderSafeJson({path: getDropboxPath(path)}),\n },\n responseType: 'arraybuffer'\n };\n if (options && options.ifNoneMatch) {\n params.headers['If-None-Match'] = options.ifNoneMatch;\n }\n\n return this._request('GET', DOWNLOAD_URL, params).then(resp => {\n const status = resp.status;\n let meta, body, mime, rev;\n if (status !== 200 && status !== 409) {\n return Promise.resolve({statusCode: status});\n }\n meta = resp.getResponseHeader('Dropbox-API-Result');\n //first encode the response as text, and later check if\n //text appears to actually be binary data\n return getTextFromArrayBuffer(resp.response, 'UTF-8').then(responseText => {\n body = responseText;\n if (status === 409) {\n meta = body;\n }\n\n try {\n meta = JSON.parse(meta);\n } catch(e) {\n return Promise.reject(e);\n }\n\n if (status === 409) {\n if (compareApiError(meta, ['path', 'not_found'])) {\n return {statusCode: 404};\n }\n return Promise.reject(new Error('API error while downloading file (\"' + path + '\"): ' + meta.error_summary));\n }\n\n mime = resp.getResponseHeader('Content-Type');\n rev = meta.rev;\n this._revCache.set(path, rev);\n this._shareIfNeeded(path); // There doesn't appear to be a need to await this.\n\n if (shouldBeTreatedAsBinary(responseText, mime)) {\n // return unprocessed response\n body = resp.response;\n } else {\n // handling json (always try)\n try {\n body = JSON.parse(body);\n mime = 'application/json; charset=UTF-8';\n } catch(e) {\n //Failed parsing Json, assume it is something else then\n }\n }\n\n return {\n statusCode: status,\n body: body,\n contentType: mime,\n revision: rev\n };\n });\n });\n }\n\n /**\n * Checks for the path in ``_revCache`` and decides based on that if file\n * has changed.\n *\n * Compatible with ``WireClient``\n *\n * Calls ``Dropbox.share`` afterwards to fill ``_itemRefs``.\n *\n * @param {string} path - path of the folder to put, with leading slash\n * @param {XMLHttpRequestBodyInit} body - Blob | BufferSource | FormData | URLSearchParams | string\n * @param {string} contentType - MIME type of body\n * @param {Object} options\n * @param {string} options.ifNoneMatch - When *, only create or update the file if it doesn't yet exist\n * @param {string} options.ifMatch - Only saves if this matches current revision\n * @returns {Promise} Resolves with an object containing the status code,\n * content-type and revision\n * @protected\n */\n async put (path: string, body, contentType: string, options: { ifMatch?: string; ifNoneMatch?: string } = {}): Promise {\n if (!this.connected) {\n throw new Error(\"not connected (path: \" + path + \")\");\n }\n\n // check if file has changed and return 412\n const savedRev = this._revCache.get(path);\n if (options && options.ifMatch &&\n savedRev && (savedRev !== options.ifMatch)) {\n return {statusCode: 412, revision: savedRev};\n }\n if (options && (options.ifNoneMatch === '*') &&\n savedRev && (savedRev !== 'rev')) {\n return {statusCode: 412, revision: savedRev};\n }\n\n if ((!contentType.match(/charset=/)) && isBinaryData(body)) {\n contentType += '; charset=binary';\n }\n\n if (body.length > 150 * 1024 * 1024) {\n //https://www.dropbox.com/developers/core/docs#chunked-upload\n throw new Error(\"Cannot upload file larger than 150MB\");\n }\n\n const needsMetadata = options && (options.ifMatch || (options.ifNoneMatch === '*'));\n const uploadParams = {\n body: body,\n contentType: contentType,\n path: path\n };\n\n if (needsMetadata) {\n const metadata = await this._getMetadata(path);\n if (options && (options.ifNoneMatch === '*') && metadata) {\n // if !!metadata === true, the file exists\n return {\n statusCode: 412,\n revision: metadata.rev\n };\n }\n\n if (options && options.ifMatch && metadata && (metadata.rev !== options.ifMatch)) {\n return {\n statusCode: 412,\n revision: metadata.rev\n };\n }\n }\n const result = await this._uploadSimple(uploadParams);\n this._shareIfNeeded(path); // There doesn't appear to be a need to await this.\n return result;\n }\n\n /**\n * Checks for the path in ``_revCache`` and decides based on that if file\n * has changed.\n *\n * Compatible with ``WireClient.delete``\n *\n * Calls ``Dropbox.share`` afterwards to fill ``_itemRefs``.\n *\n * @param {string} path - path of the folder to delete, with leading slash\n * @param {Object} options\n *\n * @protected\n */\n async 'delete' (path: string, options: { ifMatch?: string } = {}): Promise {\n if (!this.connected) {\n throw new Error(\"not connected (path: \" + path + \")\");\n }\n\n // check if file has changed and return 412\n const savedRev = this._revCache.get(path);\n if (options?.ifMatch && savedRev && (options.ifMatch !== savedRev)) {\n return { statusCode: 412, revision: savedRev };\n }\n\n if (options?.ifMatch) {\n const metadata = await this._getMetadata(path);\n if (options?.ifMatch && metadata && (metadata.rev !== options.ifMatch)) {\n return {\n statusCode: 412,\n revision: metadata.rev\n };\n }\n }\n\n return this._deleteSimple(path);\n }\n\n /**\n * Calls share, if the provided path resides in a public folder.\n * @private\n */\n _shareIfNeeded (path: string): Promise {\n if (path.match(/^\\/public\\/.*[^/]$/) && this._itemRefs[path] === undefined) {\n return this.share(path);\n }\n }\n\n /**\n * Gets a publicly-accessible URL for the path from Dropbox and stores it\n * in ``_itemRefs``.\n *\n * @return {Promise} a promise for the URL\n *\n * @private\n */\n share (path: string): Promise {\n const options = {\n body: {path: getDropboxPath(path)}\n };\n\n return this._request('POST', CREATE_SHARED_URL, options).then((response) => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.reject(new Error('Invalid response status:' + response.status));\n }\n\n let body;\n\n try {\n body = JSON.parse(response.responseText);\n } catch (e) {\n return Promise.reject(new Error('Invalid response body: ' + response.responseText));\n }\n\n if (response.status === 409) {\n if (compareApiError(body, ['shared_link_already_exists'])) {\n return this._getSharedLink(path);\n }\n\n return Promise.reject(new Error('API error: ' + body.error_summary));\n }\n\n return Promise.resolve(body.url);\n }).then((link) => {\n this._itemRefs[path] = link;\n\n if (hasLocalStorage) {\n localStorage.setItem(SETTINGS_KEY+':shares', JSON.stringify(this._itemRefs));\n }\n\n return Promise.resolve(link);\n }, (error) => {\n error.message = 'Sharing Dropbox file or folder (\"' + path + '\") failed: ' + error.message;\n return Promise.reject(error);\n });\n }\n\n /**\n * Fetches the user's info from dropbox and returns a promise for it.\n *\n * @return {Promise} a promise for user info object (email - the user's email address)\n *\n * @protected\n */\n info (): Promise<{email: string}> {\n return this._request('POST', ACCOUNT_URL, {}).then(function (response) {\n let email;\n\n try {\n const info = JSON.parse(response.responseText);\n email = info?.email;\n } catch (e) {\n return Promise.reject(new Error('Could not query current account info: Invalid API response: ' + response.responseText));\n }\n\n return Promise.resolve({\n email: email\n });\n });\n }\n\n /**\n * Makes a network request.\n *\n * @param {string} method - Request method\n * @param {string} url - Target URL\n * @param {object} options - Request options\n * @param {number} numAttempts - # of times same request repeated\n * @returns {Promise} Resolves with the response of the network request\n *\n * @private\n */\n async _request (method: string, url: string, options, numAttempts = 1): Promise {\n if (this.isForbiddenRequestMethod(method, url)) {\n throw `Don't use ${method} on directories!`;\n }\n\n if (! this.token) { throw new UnauthorizedError(\"No access token\"); }\n\n if (!options.headers) { options.headers = {}; }\n options.headers['Authorization'] = 'Bearer ' + this.token;\n\n if (typeof options.body === 'object' && !isBinaryData(options.body)) {\n options.body = JSON.stringify(options.body);\n options.headers['Content-Type'] = 'application/json; charset=UTF-8';\n }\n\n this.rs._emit('wire-busy', {\n method: method,\n isFolder: isFolder(url)\n });\n\n try {\n const xhr = await requestWithTimeout(method, url, options);\n if (!this.online) {\n this.online = true;\n this.rs._emit('network-online');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(url),\n success: true\n });\n if (xhr?.status === 401 && this.refreshToken) {\n if (numAttempts >= NUM_RETRIES) {\n console.error(`Abandoned after ${numAttempts} attempts: ${method} ${url}`);\n return xhr;\n } else {\n this.rs._emit('wire-busy', {\n method: method,\n isFolder: isFolder(url)\n });\n await Authorize.refreshAccessToken(this.rs, this, this.refreshToken);\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(url),\n success: true\n });\n // re-runs original request\n return this._request(method, url, options, numAttempts + 1);\n }\n } else if ([503, 429].includes(xhr?.status)) {\n // 503 Service Unavailable; 429 Too Many Requests\n if (this.online) {\n this.online = false;\n this.rs._emit('network-offline');\n }\n\n if (numAttempts >= NUM_RETRIES) {\n console.warn(`Abandoned after ${numAttempts} attempts: ${method} ${url}`);\n return xhr;\n } else {\n await new Promise(resolve => setTimeout(resolve, retryAfterMs(xhr)));\n // re-runs original request\n return this._request(method, url, options, numAttempts+1);\n }\n } else {\n\n return xhr;\n }\n } catch (error) {\n if (this.online) {\n this.online = false;\n this.rs._emit('network-offline');\n }\n this.rs._emit('wire-done', {\n method: method,\n isFolder: isFolder(url),\n success: false\n });\n throw error;\n }\n }\n\n /**\n * Fetches the revision of all the files from dropbox API and puts them\n * into ``_revCache``. These values can then be used to determine if\n * something has changed.\n *\n * @private\n */\n fetchDelta (...args: undefined[]): Promise {\n // If fetchDelta was already called, and didn't finish, return the existing\n // promise instead of calling Dropbox API again\n if (this._fetchDeltaPromise) {\n return this._fetchDeltaPromise;\n }\n\n /** This should resolve (with no value) on success, and reject on error. */\n const fetch = async (cursor: string) => {\n let url;\n let requestBody;\n\n if (typeof cursor === 'string') {\n url = CONTINUE_URL;\n requestBody = { cursor };\n } else {\n url = FOLDER_URL;\n requestBody = {\n path: PATH_PREFIX,\n recursive: true,\n include_deleted: true\n };\n }\n\n try {\n const response = await this._request('POST', url, {body: requestBody});\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n\n if (response.status !== 200 && response.status !== 409) {\n throw new Error('Invalid response status: ' + response.status);\n }\n\n let responseBody;\n\n try {\n responseBody = JSON.parse(response.responseText);\n } catch (e) {\n throw new Error('Invalid response body: ' + response.responseText);\n }\n\n if (response.status === 409) {\n if (compareApiError(responseBody, ['path', 'not_found'])) {\n responseBody = {\n cursor: null,\n entries: [],\n has_more: false\n };\n } else {\n throw new Error('API returned an error: ' + responseBody.error_summary);\n }\n }\n\n if (!cursor) {\n //we are doing a complete fetch, so propagation would introduce unnecessary overhead\n this._revCache.deactivatePropagation();\n }\n\n responseBody.entries.forEach(entry => {\n const path = entry.path_display.slice(PATH_PREFIX.length);\n\n if (entry['.tag'] === 'deleted') {\n // there's no way to know whether the entry was a file or a folder\n this._revCache.delete(path);\n this._revCache.delete(path + '/');\n } else if (entry['.tag'] === 'file') {\n this._revCache.set(path, entry.rev);\n }\n });\n\n this._fetchDeltaCursor = responseBody.cursor;\n if (responseBody.has_more) {\n return fetch(responseBody.cursor);\n } else {\n this._revCache.activatePropagation();\n this._initialFetchDone = true;\n }\n } catch (error) {\n if (error === 'timeout') {\n // Offline is handled elsewhere already, just ignore it here\n return;\n } else {\n throw error;\n }\n }\n };\n\n this._fetchDeltaPromise = fetch(this._fetchDeltaCursor).catch(error => {\n if (typeof(error) === 'object' && 'message' in error) {\n error.message = 'Dropbox: fetchDelta: ' + error.message;\n } else {\n error = `Dropbox: fetchDelta: ${error}`;\n }\n this.rs._emit('error', error);\n this._fetchDeltaPromise = null;\n return Promise.reject(error);\n }).then(() => {\n this._fetchDeltaPromise = null;\n return Promise.resolve(args);\n });\n\n return this._fetchDeltaPromise;\n }\n\n /**\n * Gets metadata for a path (can point to either a file or a folder).\n *\n * @param {string} path - the path to get metadata for\n *\n * @returns {Promise} A promise for the metadata\n *\n * @private\n */\n _getMetadata (path: string): Promise {\n const requestBody = {\n path: getDropboxPath(path)\n };\n\n return this._request('POST', METADATA_URL, { body: requestBody }).then((response) => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.reject(new Error('Invalid response status:' + response.status));\n }\n\n let responseBody;\n\n try {\n responseBody = JSON.parse(response.responseText);\n } catch (e) {\n return Promise.reject(new Error('Invalid response body: ' + response.responseText));\n }\n\n if (response.status === 409) {\n if (compareApiError(responseBody, ['path', 'not_found'])) {\n return Promise.resolve();\n }\n\n return Promise.reject(new Error('API error: ' + responseBody.error_summary));\n }\n\n return Promise.resolve(responseBody);\n }).then(undefined, (error) => {\n error.message = 'Could not load metadata for file or folder (\"' + path + '\"): ' + error.message;\n return Promise.reject(error);\n });\n }\n\n /**\n * Upload a simple file (the size is no more than 150MB).\n *\n * @param {Object} params\n * @param {string} params.ifMatch - Only update the file if its ETag\n * matches this string\n * @param {string} params.path - path of the file\n * @param {string} params.body - contents of the file to upload\n * @param {string} params.contentType - mime type of the file *\n * @return {Promise} A promise for an object with the following structure:\n * statusCode - HTTP status code\n * revision - revision of the newly-created file, if any\n *\n * @private\n */\n _uploadSimple (params: { body: XMLHttpRequestBodyInit; contentType?: string; path: string; ifMatch?: string; }): Promise {\n const args = {\n path: getDropboxPath(params.path),\n mode: { '.tag': 'overwrite', update: undefined },\n mute: true\n };\n\n if (params.ifMatch) {\n args.mode = { '.tag': 'update', update: params.ifMatch };\n }\n\n return this._request('POST', UPLOAD_URL, {\n body: params.body,\n headers: {\n 'Content-Type': 'application/octet-stream',\n 'Dropbox-API-Arg': httpHeaderSafeJson(args)\n }\n }).then(response => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.resolve({statusCode: response.status});\n }\n\n let body;\n\n try {\n body = JSON.parse(response.responseText);\n } catch (e) {\n return Promise.reject(new Error('Invalid API result: ' + response.responseText));\n }\n\n if (response.status === 409) {\n if (compareApiError(body, ['path', 'conflict'])) {\n return this._getMetadata(params.path).then(function (metadata) {\n return Promise.resolve({\n statusCode: 412,\n revision: metadata.rev\n });\n });\n }\n this.rs._emit('error', new Error(body.error_summary));\n return Promise.resolve({statusCode: response.status});\n }\n\n this._revCache.set(params.path, body.rev);\n\n return Promise.resolve({ statusCode: response.status, revision: body.rev });\n });\n }\n\n /**\n * Deletes a file or a folder.\n *\n * @param {string} path - the path to delete\n *\n * @returns {Promise} A promise for an object with the following structure:\n * statusCode - HTTP status code\n *\n * @private\n */\n _deleteSimple (path: string): Promise {\n const requestBody = { path: getDropboxPath(path) };\n\n return this._request('POST', DELETE_URL, { body: requestBody }).then((response) => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.resolve({statusCode: response.status});\n }\n\n let responseBody;\n\n try {\n responseBody = JSON.parse(response.responseText);\n } catch (e) {\n return Promise.reject(new Error('Invalid response body: ' + response.responseText));\n }\n\n if (response.status === 409) {\n if (compareApiError(responseBody, ['path_lookup', 'not_found'])) {\n return Promise.resolve({statusCode: 404});\n }\n this.rs._emit('error', new Error(responseBody.error_summary));\n }\n\n return Promise.resolve({statusCode: response.status});\n }).then(result => {\n if (result.statusCode === 200 || result.statusCode === 404) {\n this._revCache.delete(path);\n delete this._itemRefs[path];\n }\n return Promise.resolve(result);\n }, (error) => {\n error.message = 'Could not delete Dropbox file or folder (\"' + path + '\"): ' + error.message;\n return Promise.reject(error);\n });\n }\n\n /**\n * Requests the link for an already-shared file or folder.\n *\n * @param {string} path - path to the file or folder\n *\n * @returns {Promise} A promise for the shared link\n *\n * @private\n */\n async _getSharedLink (path: string): Promise {\n const options = {\n body: {\n path: getDropboxPath(path),\n direct_only: true\n }\n };\n\n return this._request('POST', LIST_SHARED_URL, options).then((response) => {\n if (response.status !== 200 && response.status !== 409) {\n return Promise.reject(new Error('Invalid response status: ' + response.status));\n }\n\n let body;\n\n try {\n body = JSON.parse(response.responseText);\n } catch (e) {\n return Promise.reject(new Error('Invalid response body: ' + response.responseText));\n }\n\n if (response.status === 409) {\n return Promise.reject(new Error('API error: ' + body?.error_summary || response.responseText));\n }\n\n if (!body.links.length) {\n return Promise.reject(new Error('No links returned'));\n }\n\n return Promise.resolve(body.links[0].url);\n }, error => {\n error.message = 'Could not get link to a shared file or folder (\"' + path + '\"): ' + error.message;\n return Promise.reject(error);\n });\n }\n\n /**\n * Initialize the Dropbox backend.\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @protected\n */\n static _rs_init (rs: RemoteStorage): void {\n hasLocalStorage = localStorageAvailable();\n if ( rs.apiKeys.dropbox ) {\n rs.dropbox = new Dropbox(rs);\n }\n if (rs.backend === 'dropbox') {\n hookIt(rs);\n }\n }\n\n /**\n * Inform about the availability of the Dropbox backend.\n *\n * @returns {Boolean}\n *\n * @protected\n */\n static _rs_supported (): boolean {\n return true;\n }\n\n /**\n * Remove Dropbox as a backend.\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @protected\n */\n static _rs_cleanup (rs: RemoteStorage): void {\n unHookIt(rs);\n if (hasLocalStorage){\n localStorage.removeItem(SETTINGS_KEY);\n }\n rs.setBackend(undefined);\n }\n}\n\n/**\n * Hooking the sync\n *\n * TODO: document\n */\nfunction hookSync(rs, ...args): void {\n if (rs._dropboxOrigSync) { return; } // already hooked\n rs._dropboxOrigSync = rs.sync.sync.bind(rs.sync);\n rs.sync.sync = function () {\n return this.dropbox.fetchDelta(rs, ...args).\n then(rs._dropboxOrigSync, function (err) {\n rs._emit('error', new SyncError(err));\n rs._emit('sync-done');\n });\n }.bind(rs);\n}\n\n/**\n * Unhooking the sync\n *\n * TODO: document\n */\nfunction unHookSync(rs): void {\n if (! rs._dropboxOrigSync) { return; } // not hooked\n rs.sync.sync = rs._dropboxOrigSync;\n delete rs._dropboxOrigSync;\n}\n\n/**\n * Hook RemoteStorage.syncCycle as it's the first function called\n * after RemoteStorage.sync is initialized, so we can then hook\n * the sync function\n * @param {object} rs RemoteStorage instance\n * @param {array} args remaining arguments\n */\nfunction hookSyncCycle(rs, ...args): void {\n if (rs._dropboxOrigSyncCycle) { return; } // already hooked\n rs._dropboxOrigSyncCycle = rs.syncCycle;\n rs.syncCycle = () => {\n if (rs.sync) {\n hookSync(rs);\n rs._dropboxOrigSyncCycle(rs, ...args);\n unHookSyncCycle(rs);\n } else {\n throw new Error('expected sync to be initialized by now');\n }\n };\n}\n\n/**\n * Restore RemoteStorage's syncCycle original implementation\n * @param {object} rs RemoteStorage instance\n */\nfunction unHookSyncCycle(rs): void {\n if (!rs._dropboxOrigSyncCycle) { return; } // not hooked\n rs.syncCycle = rs._dropboxOrigSyncCycle;\n delete rs._dropboxOrigSyncCycle;\n}\n\n/**\n * Overwrite BaseClient's getItemURL with our own implementation\n *\n * TODO: getItemURL still needs to be implemented\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @private\n */\nfunction hookGetItemURL (rs): void {\n if (rs._origBaseClientGetItemURL) { return; }\n rs._origBaseClientGetItemURL = BaseClient.prototype.getItemURL;\n BaseClient.prototype.getItemURL = function (/*path*/) {\n throw new Error('getItemURL is not implemented for Dropbox yet');\n };\n}\n\n/**\n * Restore BaseClient's getItemURL original implementation\n *\n * @param {object} rs - RemoteStorage instance\n *\n * @private\n */\nfunction unHookGetItemURL(rs): void {\n if (! rs._origBaseClientGetItemURL) { return; }\n BaseClient.prototype.getItemURL = rs._origBaseClientGetItemURL;\n delete rs._origBaseClientGetItemURL;\n}\n\n/**\n * TODO: document\n */\nfunction hookRemote(rs): void {\n if (rs._origRemote) { return; }\n rs._origRemote = rs.remote;\n rs.remote = rs.dropbox;\n}\n\n/**\n * TODO: document\n */\nfunction unHookRemote(rs): void {\n if (rs._origRemote) {\n rs.remote = rs._origRemote;\n delete rs._origRemote;\n }\n}\n\n/**\n * TODO: document\n */\nfunction hookIt(rs: RemoteStorage): void {\n hookRemote(rs);\n if (rs.sync) {\n hookSync(rs);\n } else {\n // when sync is not available yet, we hook the syncCycle function which is called\n // right after sync is initialized\n hookSyncCycle(rs);\n }\n hookGetItemURL(rs);\n}\n\n/**\n * TODO: document\n */\nfunction unHookIt(rs: RemoteStorage): void {\n unHookRemote(rs);\n unHookSync(rs);\n unHookGetItemURL(rs);\n unHookSyncCycle(rs);\n}\n\ninterface Dropbox extends EventHandling {}\napplyMixins(Dropbox, [EventHandling]);\n\nexport = Dropbox;\n","'use strict';\n\nimport WebFinger from 'webfinger.js';\nimport type { StorageInfo } from './interfaces/storage_info';\nimport log from './log';\nimport { globalContext, localStorageAvailable } from './util';\n\n// feature detection flags\nlet haveXMLHttpRequest, hasLocalStorage;\n\n// used to store settings in localStorage\nconst SETTINGS_KEY = 'remotestorage:discover';\n\n// cache loaded from localStorage\n// TODO use class property\nlet cachedInfo = {};\n\n/**\n * This function deals with the Webfinger lookup, discovering a connecting\n * user's storage details.\n *\n * @param {string} userAddress - user@host or URL\n *\n * @returns {Promise} A promise for an object with the following properties.\n * href - Storage base URL,\n * storageApi - RS protocol version,\n * authUrl - OAuth URL,\n * properties - Webfinger link properties\n **/\n\nconst Discover = function Discover(userAddress: string): Promise {\n return new Promise((resolve, reject) => {\n\n if (userAddress in cachedInfo) {\n return resolve(cachedInfo[userAddress]);\n }\n\n const webFinger = new WebFinger({\n tls_only: false,\n uri_fallback: true,\n request_timeout: 5000\n });\n\n return webFinger.lookup(userAddress, function (err, response) {\n if (err) {\n return reject(err);\n } else if ((typeof response.idx.links.remotestorage !== 'object') ||\n (typeof response.idx.links.remotestorage.length !== 'number') ||\n (response.idx.links.remotestorage.length <= 0)) {\n log(\"[Discover] WebFinger record for \" + userAddress + \" does not have remotestorage defined in the links section \", JSON.stringify(response.json));\n return reject(\"WebFinger record for \" + userAddress + \" does not have remotestorage defined in the links section.\");\n }\n\n const rs = response.idx.links.remotestorage[0];\n const authURL = rs.properties['http://tools.ietf.org/html/rfc6749#section-4.2'] ||\n rs.properties['auth-endpoint'];\n const storageApi = rs.properties['http://remotestorage.io/spec/version'] ||\n rs.type;\n\n // cache fetched data\n cachedInfo[userAddress] = {\n href: rs.href,\n storageApi: storageApi,\n authURL: authURL,\n properties: rs.properties\n };\n\n if (hasLocalStorage) {\n localStorage[SETTINGS_KEY] = JSON.stringify({ cache: cachedInfo });\n }\n\n return resolve(cachedInfo[userAddress]);\n });\n });\n};\n\nDiscover.DiscoveryError = function(message) {\n this.name = 'DiscoveryError';\n this.message = message;\n this.stack = (new Error()).stack;\n};\nDiscover.DiscoveryError.prototype = Object.create(Error.prototype);\nDiscover.DiscoveryError.prototype.constructor = Discover.DiscoveryError;\n\nDiscover._rs_init = function (/*remoteStorage*/): void {\n hasLocalStorage = localStorageAvailable();\n if (hasLocalStorage) {\n try {\n const settings = JSON.parse(localStorage[SETTINGS_KEY]);\n cachedInfo = settings.cache;\n } catch(e) {\n /* empty */\n }\n }\n};\n\nDiscover._rs_supported = function (): boolean {\n haveXMLHttpRequest = Object.prototype.hasOwnProperty.call(globalContext, 'XMLHttpRequest');\n return haveXMLHttpRequest;\n};\n\nDiscover._rs_cleanup = function (): void {\n if (hasLocalStorage) {\n delete localStorage[SETTINGS_KEY];\n }\n};\n\n\nexport = Discover;\n","import EventHandling from './eventhandling';\nimport { applyMixins } from './util';\n\nclass Env {\n hiddenProperty: \"hidden\" | \"mozHidden\" | \"msHidden\" | \"webkitHidden\";\n visibilityChangeEvent: \"visibilitychange\" | \"mozvisibilitychange\" | \"msvisibilitychange\" | \"webkitvisibilitychange\";\n mode: \"browser\" | \"node\";\n\n constructor() {\n this.addEvents([\"background\", \"foreground\"]);\n\n this.mode = typeof(window) !== 'undefined' ? 'browser' : 'node';\n\n if (this.mode === 'browser') {\n this.setBrowserPrefixedNames();\n document.addEventListener(this.visibilityChangeEvent, this.setVisibility.bind(this), false);\n this.setVisibility();\n }\n }\n\n setBrowserPrefixedNames (): void {\n if (this.mode !== 'browser') { return; }\n\n if (typeof document.hidden !== \"undefined\") {\n this.hiddenProperty = \"hidden\";\n this.visibilityChangeEvent = \"visibilitychange\";\n } else if (typeof document[\"mozHidden\"] !== \"undefined\") {\n this.hiddenProperty = \"mozHidden\";\n this.visibilityChangeEvent = \"mozvisibilitychange\";\n } else if (typeof document[\"msHidden\"] !== \"undefined\") {\n this.hiddenProperty = \"msHidden\";\n this.visibilityChangeEvent = \"msvisibilitychange\";\n } else if (typeof document[\"webkitHidden\"] !== \"undefined\") {\n this.hiddenProperty = \"webkitHidden\";\n this.visibilityChangeEvent = \"webkitvisibilitychange\";\n }\n }\n\n setVisibility (): void {\n if (document[this.hiddenProperty]) {\n this.goBackground();\n } else {\n this.goForeground();\n }\n }\n\n isBrowser (): boolean {\n return this.mode === \"browser\";\n }\n\n isNode (): boolean {\n return this.mode === \"node\";\n }\n\n goBackground (): void {\n this._emit(\"background\");\n }\n\n goForeground (): void {\n this._emit(\"foreground\");\n }\n\n static _rs_init (/* remoteStorage */): void {\n return;\n }\n\n static _rs_cleanup (/* remoteStorage */): void {\n return;\n }\n}\n\ninterface Env extends EventHandling {}\napplyMixins(Env, [EventHandling]);\n\nexport = Env;\n","'use strict';\n\nimport type { StorageInfo } from './interfaces/storage_info';\nimport config from './config';\nimport log from './log';\nimport {\n applyMixins,\n getGlobalContext,\n getJSONFromLocalStorage,\n extend,\n localStorageAvailable\n} from './util';\n\nimport Access from './access';\nimport Authorize from './authorize';\nimport BaseClient from './baseclient';\nimport Caching from './caching';\nimport IndexedDB from './indexeddb';\nimport InMemoryStorage from './inmemorystorage';\nimport LocalStorage from './localstorage';\nimport EventHandling from './eventhandling';\nimport GoogleDrive from './googledrive';\nimport Dropbox from './dropbox';\nimport Discover from './discover';\nimport SyncError from './sync-error';\nimport UnauthorizedError from './unauthorized-error';\nimport Features from './features';\nimport {Remote} from \"./remote\";\n\n// TODO this is assigned to RemoteStorage.util later; check if still needed\nimport * as util from './util';\nimport {AuthorizeOptions} from \"./interfaces/authorize_options\";\n\ninterface RSModule {\n name: string;\n builder; // TODO detailed type\n}\n\nconst globalContext = getGlobalContext();\n// declare global {\n// interface Window { cordova: any };\n// }\n\nlet hasLocalStorage: boolean;\n\n// TODO document and/or refactor (seems weird)\nfunction emitUnauthorized(r) {\n if (r.statusCode === 403 || r.statusCode === 401) {\n this._emit('error', new UnauthorizedError());\n }\n return Promise.resolve(r);\n}\n\n/**\n* Check if interval is valid: numeric and between 2s and 1hr inclusive\n*/\nfunction isValidInterval(interval: unknown): interval is number {\n return (typeof interval === 'number' &&\n interval >= 2000 &&\n interval <= 3600000);\n}\n\n/**\n * Constructor for the remoteStorage object/instance\n *\n * This class primarily contains feature detection code and convenience API.\n *\n * Depending on which features are built in, it contains different attributes\n * and functions. See the individual features for more information.\n *\n * @param {object} config - an optional configuration object\n * @class\n */\nclass RemoteStorage {\n /**\n * Pending get/put/delete calls\n * @private\n */\n _pending: {[key: string]: any}[] = [];\n\n /**\n * TODO: document\n */\n _cleanups: [] = [];\n\n /**\n * TODO: document\n */\n _pathHandlers: { [key: string]: any } = { change: {} };\n\n /**\n * Holds OAuth app keys for Dropbox, Google Drive\n */\n apiKeys: {googledrive?: {clientId: string}; dropbox?: {appKey: string}} = {};\n\n /**\n * Holds the feature class instance, added by feature initialization\n * TODO use type Access\n */\n access: any;\n /**\n * Holds the feature class instance, added by feature initialization\n * TODO use type Sync\n */\n sync: any;\n /**\n * Holds the feature class instance, added by feature initialization\n */\n caching: Caching;\n\n // TODO use correct types, document\n _syncTimer: any;\n syncStopped: any;\n get: any;\n put: any;\n delete: any;\n\n backend: 'remotestorage' | 'dropbox' | 'googledrive';\n\n /**\n * Holds a WireClient, GoogleDrive or Dropbox instance, added by feature initialization\n */\n remote: Remote;\n\n /*\n * Access to the local caching backend used. Usually either a\n * or instance.\n *\n * Not available, when caching is turned off.\n */\n local: IndexedDB | LocalStorage | InMemoryStorage;\n\n dropbox: Dropbox;\n googledrive: GoogleDrive;\n\n fireInitial;\n\n on: any;\n\n constructor (cfg?: object) {\n // Initial configuration property settings.\n // TODO use modern JS to merge object properties\n if (typeof cfg === 'object') { extend(config, cfg); }\n\n this.addEvents([\n 'ready', 'authing', 'connecting', 'connected', 'disconnected',\n 'not-connected', 'conflict', 'error', 'features-loaded',\n 'sync-interval-change', 'sync-req-done', 'sync-done',\n 'wire-busy', 'wire-done', 'network-offline', 'network-online'\n ]);\n\n this._setGPD({\n get: this._pendingGPD('get'),\n put: this._pendingGPD('put'),\n delete: this._pendingGPD('delete')\n });\n\n hasLocalStorage = localStorageAvailable();\n\n if (hasLocalStorage) {\n this.apiKeys = getJSONFromLocalStorage('remotestorage:api-keys') || {};\n this.setBackend(localStorage.getItem('remotestorage:backend') || 'remotestorage');\n }\n\n // Keep a reference to the orginal `on` function\n const origOn = this.on;\n\n /**\n * Register an event handler. See :ref:`rs-events` for available event names.\n *\n * @param {string} eventName - Name of the event\n * @param {function} handler - Event handler\n */\n this.on = function (eventName: string, handler): void {\n if (this._allLoaded) {\n // check if the handler should be called immediately, because the\n // event has happened already\n switch(eventName) {\n case 'features-loaded':\n setTimeout(handler, 0);\n break;\n case 'ready':\n if (this.remote) {\n setTimeout(handler, 0);\n }\n break;\n case 'connected':\n if (this.remote && this.remote.connected) {\n setTimeout(handler, 0);\n }\n break;\n case 'not-connected':\n if (this.remote && !this.remote.connected) {\n setTimeout(handler, 0);\n }\n break;\n }\n }\n\n return origOn.call(this, eventName, handler);\n };\n\n // load all features and emit `ready`\n this._init();\n\n /**\n * TODO: document\n */\n this.fireInitial = function () {\n if (this.local) {\n setTimeout(this.local.fireInitial.bind(this.local), 0);\n }\n }.bind(this);\n\n this.on('ready', this.fireInitial.bind(this));\n this.loadModules();\n }\n\n /**\n * Indicating if remoteStorage is currently connected.\n */\n get connected (): boolean {\n return this.remote.connected;\n }\n\n // FIXME: Instead of doing this, would be better to only\n // export setAuthURL / getAuthURL from RemoteStorage prototype\n static Authorize = Authorize;\n\n static SyncError = SyncError;\n static Unauthorized = UnauthorizedError;\n static DiscoveryError = Discover.DiscoveryError;\n static util = util;\n\n /**\n * Load all modules passed as arguments\n * @private\n */\n loadModules(): void {\n config.modules.forEach(this.addModule.bind(this));\n }\n\n /**\n * Initiate the OAuth authorization flow.\n *\n * This function is called by custom storage backend implementations\n * (e.g. Dropbox or Google Drive).\n *\n * @param {object} options\n * @param {string} options.authURL - URL of the authorization endpoint\n * @param {string} [options.scope] - access scope\n * @param {string} [options.clientId] - client identifier (defaults to the\n * origin of the redirectUri)\n * @private\n */\n authorize (options: AuthorizeOptions): void {\n this.access.setStorageType(this.remote.storageApi);\n if (typeof options.scope === 'undefined') {\n options.scope = this.access.scopeParameter;\n }\n\n if (globalContext.cordova) {\n options.redirectUri = config.cordovaRedirectUri;\n } else {\n const location = Authorize.getLocation();\n let redirectUri = location.origin;\n if (location.pathname !== '/') {\n redirectUri += location.pathname;\n }\n\n options.redirectUri = redirectUri;\n }\n\n if (typeof options.clientId === 'undefined') {\n options.clientId = options.redirectUri.match(/^(https?:\\/\\/[^/]+)/)[0];\n }\n\n Authorize.authorize(this, options);\n }\n\n /**\n * TODO: document\n * @private\n */\n impliedauth (storageApi?: string, redirectUri?: string): void {\n // TODO shouldn't these be default argument values?\n storageApi = storageApi || this.remote.storageApi;\n redirectUri = redirectUri || String(document.location);\n\n log('ImpliedAuth proceeding due to absent authURL; storageApi = ' + storageApi + ' redirectUri = ' + redirectUri);\n // Set a fixed access token, signalling to not send it as Bearer\n this.remote.configure({\n token: Authorize.IMPLIED_FAKE_TOKEN\n });\n document.location.href = redirectUri;\n }\n\n /**\n * @property {object} remote\n *\n * Depending on the chosen backend, this is either an instance of ``WireClient``,\n * ``Dropbox`` or ``GoogleDrive``.\n *\n * @property {boolean} remote.connected - Whether or not a remote store is connected\n * @property {boolean} remote.online - Whether last sync action was successful or not\n * @property {string} remote.userAddress - The user address of the connected user\n * @property {string} remote.properties - The properties of the WebFinger link\n */\n\n /**\n * Connect to a remoteStorage server.\n *\n * Discovers the WebFinger profile of the given user address and initiates\n * the OAuth dance.\n *\n * This method must be called *after* all required access has been claimed.\n * When using the connect widget, it will call this method itself.\n *\n * Special cases:\n *\n * 1. If a bearer token is supplied as second argument, the OAuth dance\n * will be skipped and the supplied token be used instead. This is\n * useful outside of browser environments, where the token has been\n * acquired in a different way.\n *\n * 2. If the Webfinger profile for the given user address doesn't contain\n * an auth URL, the library will assume that client and server have\n * established authorization among themselves, which will omit bearer\n * tokens in all requests later on. This is useful for example when using\n * Kerberos and similar protocols.\n *\n * @param {string} userAddress - The user address (user@host) or URL to connect to.\n * @param {string} token - (optional) A bearer token acquired beforehand\n */\n connect (userAddress: string, token?: string): void {\n this.setBackend('remotestorage');\n if (userAddress.indexOf('@') < 0 && !userAddress.match(/^(https?:\\/\\/)?[^\\s\\/$\\.?#]+\\.[^\\s]*$/)) {\n this._emit('error', new RemoteStorage.DiscoveryError(\"Not a valid user address or URL.\"));\n return;\n }\n\n // Prefix URL with https:// if it's missing\n if (userAddress.indexOf('@') < 0 && !userAddress.match(/^https?:\\/\\//)) {\n userAddress = `https://${userAddress}`;\n }\n\n if (globalContext.cordova) {\n if (typeof config.cordovaRedirectUri !== 'string') {\n this._emit('error', new RemoteStorage.DiscoveryError(\"Please supply a custom HTTPS redirect URI for your Cordova app\"));\n return;\n }\n if (!globalContext.cordova.InAppBrowser) {\n this._emit('error', new RemoteStorage.DiscoveryError(\"Please include the InAppBrowser Cordova plugin to enable OAuth\"));\n return;\n }\n }\n\n this.remote.configure({\n userAddress: userAddress\n });\n this._emit('connecting');\n\n const discoveryTimeout = setTimeout((): void => {\n this._emit('error', new RemoteStorage.DiscoveryError(\"No storage information found for this user address.\"));\n }, config.discoveryTimeout);\n\n Discover(userAddress).then((info: StorageInfo): void => {\n clearTimeout(discoveryTimeout);\n this._emit('authing');\n info.userAddress = userAddress;\n this.remote.configure(info);\n if (! this.remote.connected) {\n if (info.authURL) {\n if (typeof token === 'undefined') {\n // Normal authorization step; the default way to connect\n this.authorize({ authURL: info.authURL });\n } else if (typeof token === 'string') {\n // Token supplied directly by app/developer/user\n log('Skipping authorization sequence and connecting with known token');\n this.remote.configure({ token: token });\n } else {\n throw new Error(\"Supplied bearer token must be a string\");\n }\n } else {\n // In lieu of an excplicit authURL, assume that the browser and\n // server handle any authorization needs; for instance, TLS may\n // trigger the browser to use a client certificate, or a 401 Not\n // Authorized response may make the browser send a Kerberos ticket\n // using the SPNEGO method.\n this.impliedauth();\n }\n }\n }, (/*err*/) => {\n clearTimeout(discoveryTimeout);\n this._emit('error', new RemoteStorage.DiscoveryError(\"No storage information found for this user address.\"));\n });\n }\n\n /**\n * Reconnect the remote server to get a new authorization.\n */\n reconnect (): void {\n this.remote.configure({ token: null });\n\n if (this.backend === 'remotestorage') {\n this.connect(this.remote.userAddress);\n } else {\n this.remote.connect();\n }\n }\n\n /**\n * \"Disconnect\" from remote server to terminate current session.\n *\n * This method clears all stored settings and deletes the entire local\n * cache.\n */\n disconnect (): void {\n if (this.remote) {\n this.remote.configure({\n userAddress: null,\n href: null,\n storageApi: null,\n token: null,\n properties: null\n });\n }\n this._setGPD({\n get: this._pendingGPD('get'),\n put: this._pendingGPD('put'),\n delete: this._pendingGPD('delete')\n });\n const n = this._cleanups.length;\n let i = 0;\n\n const oneDone = (): void => {\n i++;\n if (i >= n) {\n this._init();\n // FIXME Re-enable when modules are all imports\n // log('Done cleaning up, emitting disconnected and disconnect events');\n this._emit('disconnected');\n }\n };\n\n if (n > 0) {\n this._cleanups.forEach((cleanup: (thisarg: object) => Promise) => {\n const cleanupResult = cleanup(this);\n if (typeof(cleanupResult) === 'object' && typeof(cleanupResult.then) === 'function') {\n cleanupResult.then(oneDone);\n } else {\n oneDone();\n }\n });\n } else {\n oneDone();\n }\n }\n\n /**\n * TODO: document\n * @private\n */\n setBackend (what): void {\n this.backend = what;\n if (hasLocalStorage) {\n if (what) {\n localStorage.setItem('remotestorage:backend', what);\n } else {\n localStorage.removeItem('remotestorage:backend');\n }\n }\n }\n\n /**\n * Add a \"change\" event handler to the given path. Whenever a \"change\"\n * happens (as determined by the backend, such as e.g.\n * ) and the affected path is equal to or below the\n * given 'path', the given handler is called.\n *\n * You should usually not use this method directly, but instead use the\n * \"change\" events provided by :doc:`BaseClient `\n *\n * @param {string} path - Absolute path to attach handler to\n * @param {function} handler - Handler function\n */\n onChange (path: string, handler): void {\n if (! this._pathHandlers.change[path]) {\n this._pathHandlers.change[path] = [];\n }\n this._pathHandlers.change[path].push(handler);\n }\n\n /**\n * TODO: do we still need this, now that we always instantiate the prototype?\n *\n * Enable remoteStorage logging.\n */\n enableLog (): void {\n config.logging = true;\n }\n\n /**\n * TODO: do we still need this, now that we always instantiate the prototype?\n *\n * Disable remoteStorage logging\n */\n disableLog (): void {\n config.logging = false;\n }\n\n /**\n * log\n *\n * The same as .\n */\n log (...args): void {\n log.apply(RemoteStorage, args);\n }\n\n /**\n * Set the OAuth key/ID for either GoogleDrive or Dropbox backend support.\n *\n * @param {Object} apiKeys - A config object with these properties:\n * @param {string} [apiKeys.type] - Backend type: 'googledrive' or 'dropbox'\n * @param {string} [apiKeys.key] - Client ID for GoogleDrive, or app key for Dropbox\n */\n setApiKeys (apiKeys: {[key in ApiKeyType]?: string}): void | boolean {\n const validTypes: string[] = [ApiKeyType.GOOGLE, ApiKeyType.DROPBOX];\n if (typeof apiKeys !== 'object' || !Object.keys(apiKeys).every(type => validTypes.includes(type))) {\n console.error('setApiKeys() was called with invalid arguments') ;\n return false;\n }\n\n Object.keys(apiKeys).forEach(type => {\n const key = apiKeys[type];\n if (!key) { delete this.apiKeys[type]; return; }\n\n switch(type) {\n case ApiKeyType.DROPBOX:\n this.apiKeys[ApiKeyType.DROPBOX] = { appKey: key };\n if (typeof this.dropbox === 'undefined' ||\n this.dropbox.clientId !== key) {\n Dropbox._rs_init(this);\n }\n break;\n case ApiKeyType.GOOGLE:\n this.apiKeys[ApiKeyType.GOOGLE] = { clientId: key };\n if (typeof this.googledrive === 'undefined' ||\n this.googledrive.clientId !== key) {\n GoogleDrive._rs_init(this);\n }\n break;\n }\n return true;\n });\n\n if (hasLocalStorage) {\n localStorage.setItem('remotestorage:api-keys', JSON.stringify(this.apiKeys));\n }\n\n }\n\n /**\n * Set redirect URI to be used for the OAuth redirect within the\n * in-app-browser window in Cordova apps.\n *\n * @param uri - A valid HTTP(S) URI\n */\n setCordovaRedirectUri (uri: string): void {\n if (typeof uri !== 'string' || !uri.match(/http(s)?:\\/\\//)) {\n throw new Error(\"Cordova redirect URI must be a URI string\");\n }\n config.cordovaRedirectUri = uri;\n }\n\n //\n // FEATURES INITIALIZATION\n //\n\n _init = Features.loadFeatures;\n features = Features.features;\n loadFeature = Features.loadFeature;\n featureSupported = Features.featureSupported;\n featureDone = Features.featureDone;\n featuresDone = Features.featuresDone;\n featuresLoaded = Features.featuresLoaded;\n featureInitialized = Features.featureInitialized;\n featureFailed = Features.featureFailed;\n hasFeature = Features.hasFeature;\n _setCachingModule = Features._setCachingModule;\n _collectCleanupFunctions = Features._collectCleanupFunctions;\n _fireReady = Features._fireReady;\n initFeature = Features.initFeature;\n\n //\n // GET/PUT/DELETE INTERFACE HELPERS\n //\n\n /**\n * TODO: document\n * @private\n */\n _setGPD (impl, context?) {\n function wrap(func) {\n return function (...args) {\n return func.apply(context, args)\n .then(emitUnauthorized.bind(this));\n };\n }\n this.get = wrap(impl.get);\n this.put = wrap(impl.put);\n this.delete = wrap(impl.delete);\n }\n\n /**\n * TODO: document\n * @private\n */\n _pendingGPD (methodName): () => Promise {\n return (...args) => {\n const methodArguments = Array.prototype.slice.call(args);\n return new Promise((resolve, reject) => {\n this._pending.push({\n method: methodName,\n args: methodArguments,\n promise: {\n resolve: resolve,\n reject: reject\n }\n });\n });\n };\n }\n\n /**\n * TODO: document\n * @private\n */\n _processPending (): void {\n this._pending.forEach((pending) => {\n try {\n this[pending.method](...pending.args).then(pending.promise.resolve, pending.promise.reject);\n } catch(e) {\n pending.promise.reject(e);\n }\n });\n this._pending = [];\n }\n\n //\n // CHANGE EVENT HANDLING\n //\n\n /**\n * TODO: document\n * @private\n */\n _bindChange (object: { on }): void {\n object.on('change', this._dispatchEvent.bind(this, 'change'));\n }\n\n /**\n * TODO: document\n * @private\n */\n _dispatchEvent (eventName: string, event): void {\n Object.keys(this._pathHandlers[eventName]).forEach((path: string) => {\n const pl = path.length;\n if (event.path.substr(0, pl) === path) {\n this._pathHandlers[eventName][path].forEach((handler) => {\n const ev: { relativePath?: string } = {};\n for (const key in event) { ev[key] = event[key]; }\n ev.relativePath = event.path.replace(new RegExp('^' + path), '');\n try {\n handler(ev);\n } catch(e) {\n console.error(\"'change' handler failed: \", e, e.stack);\n this._emit('error', e);\n }\n });\n }\n });\n }\n\n /**\n * This method enables you to quickly instantiate a BaseClient, which you can\n * use to directly read and manipulate data in the connected storage account.\n *\n * Please use this method only for debugging and development, and choose or\n * create a :doc:`data module ` for your app to use.\n *\n * @param path - The base directory of the BaseClient that will be returned\n * (with a leading and a trailing slash)\n *\n * @returns A client with the specified scope (category/base directory)\n */\n scope (path: string): BaseClient {\n if (typeof(path) !== 'string') {\n throw 'Argument \\'path\\' of baseClient.scope must be a string';\n }\n if (!this.access.checkPathPermission(path, 'r')) {\n console.warn('WARNING: Please use remoteStorage.access.claim() to ask for access permissions first: https://remotestoragejs.readthedocs.io/en/latest/js-api/access.html#claim');\n }\n return new BaseClient(this, path);\n }\n\n /**\n * Get the value of the sync interval when application is in the foreground\n *\n * @returns {number} A number of milliseconds\n */\n getSyncInterval (): number {\n return config.syncInterval;\n }\n\n /**\n * Set the value of the sync interval when application is in the foreground\n *\n * @param interval - Sync interval in milliseconds (between 2000 and 3600000 [1 hour])\n */\n setSyncInterval (interval: number): void {\n if (!isValidInterval(interval)) {\n throw interval + \" is not a valid sync interval\";\n }\n const oldValue = config.syncInterval;\n config.syncInterval = interval;\n this._emit('sync-interval-change', {oldValue: oldValue, newValue: interval});\n }\n\n /**\n * Get the value of the sync interval when application is in the background\n *\n * @returns A number of milliseconds\n */\n getBackgroundSyncInterval (): number {\n return config.backgroundSyncInterval;\n }\n\n /**\n * Set the value of the sync interval when the application is in the\n * background\n *\n * @param interval - Sync interval in milliseconds (between 2000 and 3600000 [1 hour])\n */\n setBackgroundSyncInterval (interval: number): void {\n if (!isValidInterval(interval)) {\n throw interval + \" is not a valid sync interval\";\n }\n const oldValue = config.backgroundSyncInterval;\n config.backgroundSyncInterval = interval;\n this._emit('sync-interval-change', {oldValue: oldValue, newValue: interval});\n }\n\n /**\n * Get the value of the current sync interval. Can be background or\n * foreground, custom or default.\n *\n * @returns {number} A number of milliseconds\n */\n getCurrentSyncInterval (): number {\n return config.isBackground ? config.backgroundSyncInterval : config.syncInterval;\n }\n\n /**\n * Get the value of the current network request timeout\n *\n * @returns {number} A number of milliseconds\n */\n getRequestTimeout (): number {\n return config.requestTimeout;\n }\n\n /**\n * Set the timeout for network requests.\n *\n * @param timeout - Timeout in milliseconds\n */\n setRequestTimeout (timeout: number): void {\n if (typeof timeout !== 'number') {\n throw timeout + \" is not a valid request timeout\";\n }\n config.requestTimeout = timeout;\n }\n\n /**\n * TODO: document\n * @private\n */\n syncCycle (): void {\n if (!this.sync || this.sync.stopped) { return; }\n\n this.on('sync-done', (): void => {\n // FIXME Re-enable when modules are all imports\n // log('[Sync] Sync done. Setting timer to', this.getCurrentSyncInterval());\n if (this.sync && !this.sync.stopped) {\n if (this._syncTimer) {\n clearTimeout(this._syncTimer);\n this._syncTimer = undefined;\n }\n this._syncTimer = setTimeout(this.sync.sync.bind(this.sync), this.getCurrentSyncInterval());\n }\n });\n\n this.sync.sync();\n }\n\n /**\n * Start synchronization with remote storage, downloading and uploading any\n * changes within the cached paths.\n *\n * Please consider: local changes will attempt sync immediately, and remote\n * changes should also be synced timely when using library defaults. So\n * this is mostly useful for letting users sync manually, when pressing a\n * sync button for example. This might feel safer to them sometimes, esp.\n * when shifting between offline and online a lot.\n *\n * @returns {Promise} A Promise which resolves when the sync has finished\n */\n startSync (): Promise {\n if (!config.cache) {\n console.warn('Nothing to sync, because caching is disabled.');\n return Promise.resolve();\n }\n this.sync.stopped = false;\n this.syncStopped = false;\n return this.sync.sync();\n }\n\n /**\n * Stop the periodic synchronization.\n */\n stopSync (): void {\n clearTimeout(this._syncTimer);\n this._syncTimer = undefined;\n\n if (this.sync) {\n // FIXME Re-enable when modules are all imports\n // log('[Sync] Stopping sync');\n this.sync.stopped = true;\n } else {\n // The sync class has not been initialized yet, so we make sure it will\n // not start the syncing process as soon as it's initialized.\n // FIXME Re-enable when modules are all imports\n // log('[Sync] Will instantiate sync stopped');\n this.syncStopped = true;\n }\n }\n\n /*\n * Add remoteStorage data module\n *\n * @param {Object} module - module object needs following properies:\n * @param {string} [module.name] - Name of the module\n * @param {function} [module.builder] - Builder function defining the module\n *\n * The module builder function should return an object containing another\n * object called exports, which will be exported to this \n * instance under the module's name. So when defining a locations module,\n * like in the example below, it would be accessible via\n * `remoteStorage.locations`, which would in turn have a `features` and a\n * `collections` property.\n *\n * The function receives a private and a public client, which are both\n * instances of . In the following example, the\n * scope of privateClient is `/locations` and the scope of publicClient is\n * `/public/locations`.\n *\n * @example\n * RemoteStorage.addModule({name: 'locations', builder: function (privateClient, publicClient) {\n * return {\n * exports: {\n * features: privateClient.scope('features/').defaultType('feature'),\n * collections: privateClient.scope('collections/').defaultType('feature-collection')\n * }\n * };\n * }});\n */\n addModule (module: RSModule): void {\n const moduleName = module.name;\n const moduleBuilder = module.builder;\n\n Object.defineProperty(this, moduleName, {\n configurable: true,\n get: function () {\n const instance = this._loadModule(moduleName, moduleBuilder);\n Object.defineProperty(this, moduleName, {\n value: instance\n });\n return instance;\n }\n });\n\n if (moduleName.indexOf('-') !== -1) {\n const camelizedName = moduleName.replace(/\\-[a-z]/g, function (s) {\n return s[1].toUpperCase();\n });\n\n Object.defineProperty(this, camelizedName, {\n get: function () {\n return this[moduleName];\n }\n });\n }\n }\n\n /**\n * Load module\n * @private\n */\n _loadModule (moduleName: string, moduleBuilder): { [key: string]: unknown } {\n if (moduleBuilder) {\n const module = moduleBuilder(\n new BaseClient(this, '/' + moduleName + '/'),\n new BaseClient(this, '/public/' + moduleName + '/')\n );\n return module.exports;\n } else {\n throw \"Unknown module: \" + moduleName;\n }\n }\n}\n\n/**\n * @property access\n *\n * Tracking claimed access scopes. A instance.\n*/\nObject.defineProperty(RemoteStorage.prototype, 'access', {\n get: function() {\n const access = new Access();\n Object.defineProperty(this, 'access', {\n value: access\n });\n return access;\n },\n configurable: true\n});\n\n// TODO Clean up/harmonize how modules are loaded and/or document this architecture properly\n//\n// At this point the remoteStorage object has not been created yet.\n// Only its prototype exists so far, so we define a self-constructing\n// property on there:\n\n/**\n * Property: caching\n *\n * Caching settings. A instance.\n */\n// FIXME Was in rs_init of Caching but don't want to require RemoteStorage from there.\nObject.defineProperty(RemoteStorage.prototype, 'caching', {\n configurable: true,\n get: function () {\n const caching = new Caching();\n Object.defineProperty(this, 'caching', {\n value: caching\n });\n return caching;\n }\n});\n\ninterface RemoteStorage extends EventHandling {}\napplyMixins(RemoteStorage, [EventHandling]);\n\nenum ApiKeyType {\n GOOGLE = 'googledrive',\n DROPBOX = 'dropbox'\n}\n\nexport = RemoteStorage;\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n try {\n var arr = new Uint8Array(1)\n arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n return arr.foo() === 42 && // typed array instances can be augmented\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length)\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length)\n }\n that.length = length\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype\n return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n if (typeof Symbol !== 'undefined' && Symbol.species &&\n Buffer[Symbol.species] === Buffer) {\n // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n Object.defineProperty(Buffer, Symbol.species, {\n value: null,\n configurable: true\n })\n }\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n } else if (size < 0) {\n throw new RangeError('\"size\" argument must not be negative')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n assertSize(size)\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0\n that = createBuffer(that, length)\n\n var actual = that.write(string, encoding)\n\n if (actual !== length) {\n // Writing a hex string, for example, that contains invalid characters will\n // cause everything after the first invalid character to be ignored. (e.g.\n // 'abxxcd' will be treated as 'ab')\n that = that.slice(0, actual)\n }\n\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = array.length < 0 ? 0 : checked(array.length) | 0\n that = createBuffer(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (byteOffset === undefined && length === undefined) {\n array = new Uint8Array(array)\n } else if (length === undefined) {\n array = new Uint8Array(array, byteOffset)\n } else {\n array = new Uint8Array(array, byteOffset, length)\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array)\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (Buffer.isBuffer(obj)) {\n var len = checked(obj.length) | 0\n that = createBuffer(that, len)\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len)\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength()` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'latin1':\n case 'binary':\n case 'base64':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n var buffer = Buffer.allocUnsafe(length)\n var pos = 0\n for (i = 0; i < list.length; ++i) {\n var buf = list[i]\n if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos)\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string\n }\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'latin1':\n case 'binary':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'latin1':\n case 'binary':\n return latin1Slice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n var i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.swap64 = function swap64 () {\n var len = this.length\n if (len % 8 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 64-bits')\n }\n for (var i = 0; i < len; i += 8) {\n swap(this, i, i + 7)\n swap(this, i + 1, i + 6)\n swap(this, i + 2, i + 5)\n swap(this, i + 3, i + 4)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart\n var y = end - start\n var len = Math.min(x, y)\n\n var thisCopy = this.slice(thisStart, thisEnd)\n var targetCopy = target.slice(start, end)\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\n// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n//\n// Arguments:\n// - buffer - a Buffer to search\n// - val - a string, Buffer, or number\n// - byteOffset - an index into `buffer`; will be clamped to an int32\n// - encoding - an optional encoding, relevant is val is a string\n// - dir - true for indexOf, false for lastIndexOf\nfunction bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {\n // Empty buffer means no match\n if (buffer.length === 0) return -1\n\n // Normalize byteOffset\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset = +byteOffset // Coerce to Number.\n if (isNaN(byteOffset)) {\n // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n byteOffset = dir ? 0 : (buffer.length - 1)\n }\n\n // Normalize byteOffset: negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = buffer.length + byteOffset\n if (byteOffset >= buffer.length) {\n if (dir) return -1\n else byteOffset = buffer.length - 1\n } else if (byteOffset < 0) {\n if (dir) byteOffset = 0\n else return -1\n }\n\n // Normalize val\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n // Finally, search either indexOf (if dir is true) or lastIndexOf\n if (Buffer.isBuffer(val)) {\n // Special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(buffer, val, byteOffset, encoding, dir)\n } else if (typeof val === 'number') {\n val = val & 0xFF // Search for a byte value [0-255]\n if (Buffer.TYPED_ARRAY_SUPPORT &&\n typeof Uint8Array.prototype.indexOf === 'function') {\n if (dir) {\n return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)\n } else {\n return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)\n }\n }\n return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding, dir) {\n var indexSize = 1\n var arrLength = arr.length\n var valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var i\n if (dir) {\n var foundIndex = -1\n for (i = byteOffset; i < arrLength; i++) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n } else {\n if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength\n for (i = byteOffset; i >= 0; i--) {\n var found = true\n for (var j = 0; j < valLength; j++) {\n if (read(arr, i + j) !== read(val, j)) {\n found = false\n break\n }\n }\n if (found) return i\n }\n }\n\n return -1\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, true)\n}\n\nBuffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, false)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction latin1Write (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'latin1':\n case 'binary':\n return latin1Write(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction latin1Slice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end)\n newBuf.__proto__ = Buffer.prototype\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start]\n }\n }\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0)\n if (code < 256) {\n val = code\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n var i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n var bytes = Buffer.isBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString())\n var len = bytes.length\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n","'use strict'\n\nexports.byteLength = byteLength\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nvar code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfor (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i]\n revLookup[code.charCodeAt(i)] = i\n}\n\n// Support decoding URL-safe base64 strings, as Node.js does.\n// See: https://en.wikipedia.org/wiki/Base64#URL_applications\nrevLookup['-'.charCodeAt(0)] = 62\nrevLookup['_'.charCodeAt(0)] = 63\n\nfunction getLens (b64) {\n var len = b64.length\n\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // Trim off extra bytes after placeholder bytes are found\n // See: https://github.com/beatgammit/base64-js/issues/42\n var validLen = b64.indexOf('=')\n if (validLen === -1) validLen = len\n\n var placeHoldersLen = validLen === len\n ? 0\n : 4 - (validLen % 4)\n\n return [validLen, placeHoldersLen]\n}\n\n// base64 is 4/3 + up to two characters of the original data\nfunction byteLength (b64) {\n var lens = getLens(b64)\n var validLen = lens[0]\n var placeHoldersLen = lens[1]\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction _byteLength (b64, validLen, placeHoldersLen) {\n return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen\n}\n\nfunction toByteArray (b64) {\n var tmp\n var lens = getLens(b64)\n var validLen = lens[0]\n var placeHoldersLen = lens[1]\n\n var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))\n\n var curByte = 0\n\n // if there are placeholders, only get up to the last complete 4 chars\n var len = placeHoldersLen > 0\n ? validLen - 4\n : validLen\n\n var i\n for (i = 0; i < len; i += 4) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 18) |\n (revLookup[b64.charCodeAt(i + 1)] << 12) |\n (revLookup[b64.charCodeAt(i + 2)] << 6) |\n revLookup[b64.charCodeAt(i + 3)]\n arr[curByte++] = (tmp >> 16) & 0xFF\n arr[curByte++] = (tmp >> 8) & 0xFF\n arr[curByte++] = tmp & 0xFF\n }\n\n if (placeHoldersLen === 2) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 2) |\n (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[curByte++] = tmp & 0xFF\n }\n\n if (placeHoldersLen === 1) {\n tmp =\n (revLookup[b64.charCodeAt(i)] << 10) |\n (revLookup[b64.charCodeAt(i + 1)] << 4) |\n (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[curByte++] = (tmp >> 8) & 0xFF\n arr[curByte++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] +\n lookup[num >> 12 & 0x3F] +\n lookup[num >> 6 & 0x3F] +\n lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp =\n ((uint8[i] << 16) & 0xFF0000) +\n ((uint8[i + 1] << 8) & 0xFF00) +\n (uint8[i + 2] & 0xFF)\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n parts.push(\n lookup[tmp >> 2] +\n lookup[(tmp << 4) & 0x3F] +\n '=='\n )\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + uint8[len - 1]\n parts.push(\n lookup[tmp >> 10] +\n lookup[(tmp >> 4) & 0x3F] +\n lookup[(tmp << 2) & 0x3F] +\n '='\n )\n }\n\n return parts.join('')\n}\n","/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */\nexports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = (nBytes * 8) - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = (nBytes * 8) - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = ((value * c) - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n","/*\r\nAuthor: Geraint Luff and others\r\nYear: 2013\r\n\r\nThis code is released into the \"public domain\" by its author(s). Anybody may use, alter and distribute the code without restriction. The author makes no guarantees, and takes no liability of any kind for use of this code.\r\n\r\nIf you find a bug or make an improvement, it would be courteous to let the author know, but it is not compulsory.\r\n*/\r\n(function (global, factory) {\r\n if (typeof define === 'function' && define.amd) {\r\n // AMD. Register as an anonymous module.\r\n define([], factory);\r\n } else if (typeof module !== 'undefined' && module.exports){\r\n // CommonJS. Define export.\r\n module.exports = factory();\r\n } else {\r\n // Browser globals\r\n global.tv4 = factory();\r\n }\r\n}(this, function () {\r\n\r\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FObject%2Fkeys\r\nif (!Object.keys) {\r\n\tObject.keys = (function () {\r\n\t\tvar hasOwnProperty = Object.prototype.hasOwnProperty,\r\n\t\t\thasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),\r\n\t\t\tdontEnums = [\r\n\t\t\t\t'toString',\r\n\t\t\t\t'toLocaleString',\r\n\t\t\t\t'valueOf',\r\n\t\t\t\t'hasOwnProperty',\r\n\t\t\t\t'isPrototypeOf',\r\n\t\t\t\t'propertyIsEnumerable',\r\n\t\t\t\t'constructor'\r\n\t\t\t],\r\n\t\t\tdontEnumsLength = dontEnums.length;\r\n\r\n\t\treturn function (obj) {\r\n\t\t\tif (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) {\r\n\t\t\t\tthrow new TypeError('Object.keys called on non-object');\r\n\t\t\t}\r\n\r\n\t\t\tvar result = [];\r\n\r\n\t\t\tfor (var prop in obj) {\r\n\t\t\t\tif (hasOwnProperty.call(obj, prop)) {\r\n\t\t\t\t\tresult.push(prop);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (hasDontEnumBug) {\r\n\t\t\t\tfor (var i=0; i < dontEnumsLength; i++) {\r\n\t\t\t\t\tif (hasOwnProperty.call(obj, dontEnums[i])) {\r\n\t\t\t\t\t\tresult.push(dontEnums[i]);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t};\r\n\t})();\r\n}\r\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create\r\nif (!Object.create) {\r\n\tObject.create = (function(){\r\n\t\tfunction F(){}\r\n\r\n\t\treturn function(o){\r\n\t\t\tif (arguments.length !== 1) {\r\n\t\t\t\tthrow new Error('Object.create implementation only accepts one parameter.');\r\n\t\t\t}\r\n\t\t\tF.prototype = o;\r\n\t\t\treturn new F();\r\n\t\t};\r\n\t})();\r\n}\r\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FisArray\r\nif(!Array.isArray) {\r\n\tArray.isArray = function (vArg) {\r\n\t\treturn Object.prototype.toString.call(vArg) === \"[object Array]\";\r\n\t};\r\n}\r\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FindexOf\r\nif (!Array.prototype.indexOf) {\r\n\tArray.prototype.indexOf = function (searchElement /*, fromIndex */ ) {\r\n\t\tif (this === null) {\r\n\t\t\tthrow new TypeError();\r\n\t\t}\r\n\t\tvar t = Object(this);\r\n\t\tvar len = t.length >>> 0;\r\n\r\n\t\tif (len === 0) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tvar n = 0;\r\n\t\tif (arguments.length > 1) {\r\n\t\t\tn = Number(arguments[1]);\r\n\t\t\tif (n !== n) { // shortcut for verifying if it's NaN\r\n\t\t\t\tn = 0;\r\n\t\t\t} else if (n !== 0 && n !== Infinity && n !== -Infinity) {\r\n\t\t\t\tn = (n > 0 || -1) * Math.floor(Math.abs(n));\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (n >= len) {\r\n\t\t\treturn -1;\r\n\t\t}\r\n\t\tvar k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);\r\n\t\tfor (; k < len; k++) {\r\n\t\t\tif (k in t && t[k] === searchElement) {\r\n\t\t\t\treturn k;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn -1;\r\n\t};\r\n}\r\n\r\n// Grungey Object.isFrozen hack\r\nif (!Object.isFrozen) {\r\n\tObject.isFrozen = function (obj) {\r\n\t\tvar key = \"tv4_test_frozen_key\";\r\n\t\twhile (obj.hasOwnProperty(key)) {\r\n\t\t\tkey += Math.random();\r\n\t\t}\r\n\t\ttry {\r\n\t\t\tobj[key] = true;\r\n\t\t\tdelete obj[key];\r\n\t\t\treturn false;\r\n\t\t} catch (e) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t};\r\n}\r\n// Based on: https://github.com/geraintluff/uri-templates, but with all the de-substitution stuff removed\r\n\r\nvar uriTemplateGlobalModifiers = {\r\n\t\"+\": true,\r\n\t\"#\": true,\r\n\t\".\": true,\r\n\t\"/\": true,\r\n\t\";\": true,\r\n\t\"?\": true,\r\n\t\"&\": true\r\n};\r\nvar uriTemplateSuffices = {\r\n\t\"*\": true\r\n};\r\n\r\nfunction notReallyPercentEncode(string) {\r\n\treturn encodeURI(string).replace(/%25[0-9][0-9]/g, function (doubleEncoded) {\r\n\t\treturn \"%\" + doubleEncoded.substring(3);\r\n\t});\r\n}\r\n\r\nfunction uriTemplateSubstitution(spec) {\r\n\tvar modifier = \"\";\r\n\tif (uriTemplateGlobalModifiers[spec.charAt(0)]) {\r\n\t\tmodifier = spec.charAt(0);\r\n\t\tspec = spec.substring(1);\r\n\t}\r\n\tvar separator = \"\";\r\n\tvar prefix = \"\";\r\n\tvar shouldEscape = true;\r\n\tvar showVariables = false;\r\n\tvar trimEmptyString = false;\r\n\tif (modifier === '+') {\r\n\t\tshouldEscape = false;\r\n\t} else if (modifier === \".\") {\r\n\t\tprefix = \".\";\r\n\t\tseparator = \".\";\r\n\t} else if (modifier === \"/\") {\r\n\t\tprefix = \"/\";\r\n\t\tseparator = \"/\";\r\n\t} else if (modifier === '#') {\r\n\t\tprefix = \"#\";\r\n\t\tshouldEscape = false;\r\n\t} else if (modifier === ';') {\r\n\t\tprefix = \";\";\r\n\t\tseparator = \";\";\r\n\t\tshowVariables = true;\r\n\t\ttrimEmptyString = true;\r\n\t} else if (modifier === '?') {\r\n\t\tprefix = \"?\";\r\n\t\tseparator = \"&\";\r\n\t\tshowVariables = true;\r\n\t} else if (modifier === '&') {\r\n\t\tprefix = \"&\";\r\n\t\tseparator = \"&\";\r\n\t\tshowVariables = true;\r\n\t}\r\n\r\n\tvar varNames = [];\r\n\tvar varList = spec.split(\",\");\r\n\tvar varSpecs = [];\r\n\tvar varSpecMap = {};\r\n\tfor (var i = 0; i < varList.length; i++) {\r\n\t\tvar varName = varList[i];\r\n\t\tvar truncate = null;\r\n\t\tif (varName.indexOf(\":\") !== -1) {\r\n\t\t\tvar parts = varName.split(\":\");\r\n\t\t\tvarName = parts[0];\r\n\t\t\ttruncate = parseInt(parts[1], 10);\r\n\t\t}\r\n\t\tvar suffices = {};\r\n\t\twhile (uriTemplateSuffices[varName.charAt(varName.length - 1)]) {\r\n\t\t\tsuffices[varName.charAt(varName.length - 1)] = true;\r\n\t\t\tvarName = varName.substring(0, varName.length - 1);\r\n\t\t}\r\n\t\tvar varSpec = {\r\n\t\t\ttruncate: truncate,\r\n\t\t\tname: varName,\r\n\t\t\tsuffices: suffices\r\n\t\t};\r\n\t\tvarSpecs.push(varSpec);\r\n\t\tvarSpecMap[varName] = varSpec;\r\n\t\tvarNames.push(varName);\r\n\t}\r\n\tvar subFunction = function (valueFunction) {\r\n\t\tvar result = \"\";\r\n\t\tvar startIndex = 0;\r\n\t\tfor (var i = 0; i < varSpecs.length; i++) {\r\n\t\t\tvar varSpec = varSpecs[i];\r\n\t\t\tvar value = valueFunction(varSpec.name);\r\n\t\t\tif (value === null || value === undefined || (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0)) {\r\n\t\t\t\tstartIndex++;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (i === startIndex) {\r\n\t\t\t\tresult += prefix;\r\n\t\t\t} else {\r\n\t\t\t\tresult += (separator || \",\");\r\n\t\t\t}\r\n\t\t\tif (Array.isArray(value)) {\r\n\t\t\t\tif (showVariables) {\r\n\t\t\t\t\tresult += varSpec.name + \"=\";\r\n\t\t\t\t}\r\n\t\t\t\tfor (var j = 0; j < value.length; j++) {\r\n\t\t\t\t\tif (j > 0) {\r\n\t\t\t\t\t\tresult += varSpec.suffices['*'] ? (separator || \",\") : \",\";\r\n\t\t\t\t\t\tif (varSpec.suffices['*'] && showVariables) {\r\n\t\t\t\t\t\t\tresult += varSpec.name + \"=\";\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tresult += shouldEscape ? encodeURIComponent(value[j]).replace(/!/g, \"%21\") : notReallyPercentEncode(value[j]);\r\n\t\t\t\t}\r\n\t\t\t} else if (typeof value === \"object\") {\r\n\t\t\t\tif (showVariables && !varSpec.suffices['*']) {\r\n\t\t\t\t\tresult += varSpec.name + \"=\";\r\n\t\t\t\t}\r\n\t\t\t\tvar first = true;\r\n\t\t\t\tfor (var key in value) {\r\n\t\t\t\t\tif (!first) {\r\n\t\t\t\t\t\tresult += varSpec.suffices['*'] ? (separator || \",\") : \",\";\r\n\t\t\t\t\t}\r\n\t\t\t\t\tfirst = false;\r\n\t\t\t\t\tresult += shouldEscape ? encodeURIComponent(key).replace(/!/g, \"%21\") : notReallyPercentEncode(key);\r\n\t\t\t\t\tresult += varSpec.suffices['*'] ? '=' : \",\";\r\n\t\t\t\t\tresult += shouldEscape ? encodeURIComponent(value[key]).replace(/!/g, \"%21\") : notReallyPercentEncode(value[key]);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tif (showVariables) {\r\n\t\t\t\t\tresult += varSpec.name;\r\n\t\t\t\t\tif (!trimEmptyString || value !== \"\") {\r\n\t\t\t\t\t\tresult += \"=\";\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (varSpec.truncate != null) {\r\n\t\t\t\t\tvalue = value.substring(0, varSpec.truncate);\r\n\t\t\t\t}\r\n\t\t\t\tresult += shouldEscape ? encodeURIComponent(value).replace(/!/g, \"%21\"): notReallyPercentEncode(value);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result;\r\n\t};\r\n\tsubFunction.varNames = varNames;\r\n\treturn {\r\n\t\tprefix: prefix,\r\n\t\tsubstitution: subFunction\r\n\t};\r\n}\r\n\r\nfunction UriTemplate(template) {\r\n\tif (!(this instanceof UriTemplate)) {\r\n\t\treturn new UriTemplate(template);\r\n\t}\r\n\tvar parts = template.split(\"{\");\r\n\tvar textParts = [parts.shift()];\r\n\tvar prefixes = [];\r\n\tvar substitutions = [];\r\n\tvar varNames = [];\r\n\twhile (parts.length > 0) {\r\n\t\tvar part = parts.shift();\r\n\t\tvar spec = part.split(\"}\")[0];\r\n\t\tvar remainder = part.substring(spec.length + 1);\r\n\t\tvar funcs = uriTemplateSubstitution(spec);\r\n\t\tsubstitutions.push(funcs.substitution);\r\n\t\tprefixes.push(funcs.prefix);\r\n\t\ttextParts.push(remainder);\r\n\t\tvarNames = varNames.concat(funcs.substitution.varNames);\r\n\t}\r\n\tthis.fill = function (valueFunction) {\r\n\t\tvar result = textParts[0];\r\n\t\tfor (var i = 0; i < substitutions.length; i++) {\r\n\t\t\tvar substitution = substitutions[i];\r\n\t\t\tresult += substitution(valueFunction);\r\n\t\t\tresult += textParts[i + 1];\r\n\t\t}\r\n\t\treturn result;\r\n\t};\r\n\tthis.varNames = varNames;\r\n\tthis.template = template;\r\n}\r\nUriTemplate.prototype = {\r\n\ttoString: function () {\r\n\t\treturn this.template;\r\n\t},\r\n\tfillFromObject: function (obj) {\r\n\t\treturn this.fill(function (varName) {\r\n\t\t\treturn obj[varName];\r\n\t\t});\r\n\t}\r\n};\r\nvar ValidatorContext = function ValidatorContext(parent, collectMultiple, errorReporter, checkRecursive, trackUnknownProperties) {\r\n\tthis.missing = [];\r\n\tthis.missingMap = {};\r\n\tthis.formatValidators = parent ? Object.create(parent.formatValidators) : {};\r\n\tthis.schemas = parent ? Object.create(parent.schemas) : {};\r\n\tthis.collectMultiple = collectMultiple;\r\n\tthis.errors = [];\r\n\tthis.handleError = collectMultiple ? this.collectError : this.returnError;\r\n\tif (checkRecursive) {\r\n\t\tthis.checkRecursive = true;\r\n\t\tthis.scanned = [];\r\n\t\tthis.scannedFrozen = [];\r\n\t\tthis.scannedFrozenSchemas = [];\r\n\t\tthis.scannedFrozenValidationErrors = [];\r\n\t\tthis.validatedSchemasKey = 'tv4_validation_id';\r\n\t\tthis.validationErrorsKey = 'tv4_validation_errors_id';\r\n\t}\r\n\tif (trackUnknownProperties) {\r\n\t\tthis.trackUnknownProperties = true;\r\n\t\tthis.knownPropertyPaths = {};\r\n\t\tthis.unknownPropertyPaths = {};\r\n\t}\r\n\tthis.errorReporter = errorReporter || defaultErrorReporter('en');\r\n\tif (typeof this.errorReporter === 'string') {\r\n\t\tthrow new Error('debug');\r\n\t}\r\n\tthis.definedKeywords = {};\r\n\tif (parent) {\r\n\t\tfor (var key in parent.definedKeywords) {\r\n\t\t\tthis.definedKeywords[key] = parent.definedKeywords[key].slice(0);\r\n\t\t}\r\n\t}\r\n};\r\nValidatorContext.prototype.defineKeyword = function (keyword, keywordFunction) {\r\n\tthis.definedKeywords[keyword] = this.definedKeywords[keyword] || [];\r\n\tthis.definedKeywords[keyword].push(keywordFunction);\r\n};\r\nValidatorContext.prototype.createError = function (code, messageParams, dataPath, schemaPath, subErrors, data, schema) {\r\n\tvar error = new ValidationError(code, messageParams, dataPath, schemaPath, subErrors);\r\n\terror.message = this.errorReporter(error, data, schema);\r\n\treturn error;\r\n};\r\nValidatorContext.prototype.returnError = function (error) {\r\n\treturn error;\r\n};\r\nValidatorContext.prototype.collectError = function (error) {\r\n\tif (error) {\r\n\t\tthis.errors.push(error);\r\n\t}\r\n\treturn null;\r\n};\r\nValidatorContext.prototype.prefixErrors = function (startIndex, dataPath, schemaPath) {\r\n\tfor (var i = startIndex; i < this.errors.length; i++) {\r\n\t\tthis.errors[i] = this.errors[i].prefixWith(dataPath, schemaPath);\r\n\t}\r\n\treturn this;\r\n};\r\nValidatorContext.prototype.banUnknownProperties = function (data, schema) {\r\n\tfor (var unknownPath in this.unknownPropertyPaths) {\r\n\t\tvar error = this.createError(ErrorCodes.UNKNOWN_PROPERTY, {path: unknownPath}, unknownPath, \"\", null, data, schema);\r\n\t\tvar result = this.handleError(error);\r\n\t\tif (result) {\r\n\t\t\treturn result;\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.addFormat = function (format, validator) {\r\n\tif (typeof format === 'object') {\r\n\t\tfor (var key in format) {\r\n\t\t\tthis.addFormat(key, format[key]);\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n\tthis.formatValidators[format] = validator;\r\n};\r\nValidatorContext.prototype.resolveRefs = function (schema, urlHistory) {\r\n\tif (schema['$ref'] !== undefined) {\r\n\t\turlHistory = urlHistory || {};\r\n\t\tif (urlHistory[schema['$ref']]) {\r\n\t\t\treturn this.createError(ErrorCodes.CIRCULAR_REFERENCE, {urls: Object.keys(urlHistory).join(', ')}, '', '', null, undefined, schema);\r\n\t\t}\r\n\t\turlHistory[schema['$ref']] = true;\r\n\t\tschema = this.getSchema(schema['$ref'], urlHistory);\r\n\t}\r\n\treturn schema;\r\n};\r\nValidatorContext.prototype.getSchema = function (url, urlHistory) {\r\n\tvar schema;\r\n\tif (this.schemas[url] !== undefined) {\r\n\t\tschema = this.schemas[url];\r\n\t\treturn this.resolveRefs(schema, urlHistory);\r\n\t}\r\n\tvar baseUrl = url;\r\n\tvar fragment = \"\";\r\n\tif (url.indexOf('#') !== -1) {\r\n\t\tfragment = url.substring(url.indexOf(\"#\") + 1);\r\n\t\tbaseUrl = url.substring(0, url.indexOf(\"#\"));\r\n\t}\r\n\tif (typeof this.schemas[baseUrl] === 'object') {\r\n\t\tschema = this.schemas[baseUrl];\r\n\t\tvar pointerPath = decodeURIComponent(fragment);\r\n\t\tif (pointerPath === \"\") {\r\n\t\t\treturn this.resolveRefs(schema, urlHistory);\r\n\t\t} else if (pointerPath.charAt(0) !== \"/\") {\r\n\t\t\treturn undefined;\r\n\t\t}\r\n\t\tvar parts = pointerPath.split(\"/\").slice(1);\r\n\t\tfor (var i = 0; i < parts.length; i++) {\r\n\t\t\tvar component = parts[i].replace(/~1/g, \"/\").replace(/~0/g, \"~\");\r\n\t\t\tif (schema[component] === undefined) {\r\n\t\t\t\tschema = undefined;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tschema = schema[component];\r\n\t\t}\r\n\t\tif (schema !== undefined) {\r\n\t\t\treturn this.resolveRefs(schema, urlHistory);\r\n\t\t}\r\n\t}\r\n\tif (this.missing[baseUrl] === undefined) {\r\n\t\tthis.missing.push(baseUrl);\r\n\t\tthis.missing[baseUrl] = baseUrl;\r\n\t\tthis.missingMap[baseUrl] = baseUrl;\r\n\t}\r\n};\r\nValidatorContext.prototype.searchSchemas = function (schema, url) {\r\n\tif (Array.isArray(schema)) {\r\n\t\tfor (var i = 0; i < schema.length; i++) {\r\n\t\t\tthis.searchSchemas(schema[i], url);\r\n\t\t}\r\n\t} else if (schema && typeof schema === \"object\") {\r\n\t\tif (typeof schema.id === \"string\") {\r\n\t\t\tif (isTrustedUrl(url, schema.id)) {\r\n\t\t\t\tif (this.schemas[schema.id] === undefined) {\r\n\t\t\t\t\tthis.schemas[schema.id] = schema;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (var key in schema) {\r\n\t\t\tif (key !== \"enum\") {\r\n\t\t\t\tif (typeof schema[key] === \"object\") {\r\n\t\t\t\t\tthis.searchSchemas(schema[key], url);\r\n\t\t\t\t} else if (key === \"$ref\") {\r\n\t\t\t\t\tvar uri = getDocumentUri(schema[key]);\r\n\t\t\t\t\tif (uri && this.schemas[uri] === undefined && this.missingMap[uri] === undefined) {\r\n\t\t\t\t\t\tthis.missingMap[uri] = uri;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n};\r\nValidatorContext.prototype.addSchema = function (url, schema) {\r\n\t//overload\r\n\tif (typeof url !== 'string' || typeof schema === 'undefined') {\r\n\t\tif (typeof url === 'object' && typeof url.id === 'string') {\r\n\t\t\tschema = url;\r\n\t\t\turl = schema.id;\r\n\t\t}\r\n\t\telse {\r\n\t\t\treturn;\r\n\t\t}\r\n\t}\r\n\tif (url === getDocumentUri(url) + \"#\") {\r\n\t\t// Remove empty fragment\r\n\t\turl = getDocumentUri(url);\r\n\t}\r\n\tthis.schemas[url] = schema;\r\n\tdelete this.missingMap[url];\r\n\tnormSchema(schema, url);\r\n\tthis.searchSchemas(schema, url);\r\n};\r\n\r\nValidatorContext.prototype.getSchemaMap = function () {\r\n\tvar map = {};\r\n\tfor (var key in this.schemas) {\r\n\t\tmap[key] = this.schemas[key];\r\n\t}\r\n\treturn map;\r\n};\r\n\r\nValidatorContext.prototype.getSchemaUris = function (filterRegExp) {\r\n\tvar list = [];\r\n\tfor (var key in this.schemas) {\r\n\t\tif (!filterRegExp || filterRegExp.test(key)) {\r\n\t\t\tlist.push(key);\r\n\t\t}\r\n\t}\r\n\treturn list;\r\n};\r\n\r\nValidatorContext.prototype.getMissingUris = function (filterRegExp) {\r\n\tvar list = [];\r\n\tfor (var key in this.missingMap) {\r\n\t\tif (!filterRegExp || filterRegExp.test(key)) {\r\n\t\t\tlist.push(key);\r\n\t\t}\r\n\t}\r\n\treturn list;\r\n};\r\n\r\nValidatorContext.prototype.dropSchemas = function () {\r\n\tthis.schemas = {};\r\n\tthis.reset();\r\n};\r\nValidatorContext.prototype.reset = function () {\r\n\tthis.missing = [];\r\n\tthis.missingMap = {};\r\n\tthis.errors = [];\r\n};\r\n\r\nValidatorContext.prototype.validateAll = function (data, schema, dataPathParts, schemaPathParts, dataPointerPath) {\r\n\tvar topLevel;\r\n\tschema = this.resolveRefs(schema);\r\n\tif (!schema) {\r\n\t\treturn null;\r\n\t} else if (schema instanceof ValidationError) {\r\n\t\tthis.errors.push(schema);\r\n\t\treturn schema;\r\n\t}\r\n\r\n\tvar startErrorCount = this.errors.length;\r\n\tvar frozenIndex, scannedFrozenSchemaIndex = null, scannedSchemasIndex = null;\r\n\tif (this.checkRecursive && data && typeof data === 'object') {\r\n\t\ttopLevel = !this.scanned.length;\r\n\t\tif (data[this.validatedSchemasKey]) {\r\n\t\t\tvar schemaIndex = data[this.validatedSchemasKey].indexOf(schema);\r\n\t\t\tif (schemaIndex !== -1) {\r\n\t\t\t\tthis.errors = this.errors.concat(data[this.validationErrorsKey][schemaIndex]);\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (Object.isFrozen(data)) {\r\n\t\t\tfrozenIndex = this.scannedFrozen.indexOf(data);\r\n\t\t\tif (frozenIndex !== -1) {\r\n\t\t\t\tvar frozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].indexOf(schema);\r\n\t\t\t\tif (frozenSchemaIndex !== -1) {\r\n\t\t\t\t\tthis.errors = this.errors.concat(this.scannedFrozenValidationErrors[frozenIndex][frozenSchemaIndex]);\r\n\t\t\t\t\treturn null;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tthis.scanned.push(data);\r\n\t\tif (Object.isFrozen(data)) {\r\n\t\t\tif (frozenIndex === -1) {\r\n\t\t\t\tfrozenIndex = this.scannedFrozen.length;\r\n\t\t\t\tthis.scannedFrozen.push(data);\r\n\t\t\t\tthis.scannedFrozenSchemas.push([]);\r\n\t\t\t}\r\n\t\t\tscannedFrozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].length;\r\n\t\t\tthis.scannedFrozenSchemas[frozenIndex][scannedFrozenSchemaIndex] = schema;\r\n\t\t\tthis.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = [];\r\n\t\t} else {\r\n\t\t\tif (!data[this.validatedSchemasKey]) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tObject.defineProperty(data, this.validatedSchemasKey, {\r\n\t\t\t\t\t\tvalue: [],\r\n\t\t\t\t\t\tconfigurable: true\r\n\t\t\t\t\t});\r\n\t\t\t\t\tObject.defineProperty(data, this.validationErrorsKey, {\r\n\t\t\t\t\t\tvalue: [],\r\n\t\t\t\t\t\tconfigurable: true\r\n\t\t\t\t\t});\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\t//IE 7/8 workaround\r\n\t\t\t\t\tdata[this.validatedSchemasKey] = [];\r\n\t\t\t\t\tdata[this.validationErrorsKey] = [];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tscannedSchemasIndex = data[this.validatedSchemasKey].length;\r\n\t\t\tdata[this.validatedSchemasKey][scannedSchemasIndex] = schema;\r\n\t\t\tdata[this.validationErrorsKey][scannedSchemasIndex] = [];\r\n\t\t}\r\n\t}\r\n\r\n\tvar errorCount = this.errors.length;\r\n\tvar error = this.validateBasic(data, schema, dataPointerPath)\r\n\t\t|| this.validateNumeric(data, schema, dataPointerPath)\r\n\t\t|| this.validateString(data, schema, dataPointerPath)\r\n\t\t|| this.validateArray(data, schema, dataPointerPath)\r\n\t\t|| this.validateObject(data, schema, dataPointerPath)\r\n\t\t|| this.validateCombinations(data, schema, dataPointerPath)\r\n\t\t|| this.validateHypermedia(data, schema, dataPointerPath)\r\n\t\t|| this.validateFormat(data, schema, dataPointerPath)\r\n\t\t|| this.validateDefinedKeywords(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n\r\n\tif (topLevel) {\r\n\t\twhile (this.scanned.length) {\r\n\t\t\tvar item = this.scanned.pop();\r\n\t\t\tdelete item[this.validatedSchemasKey];\r\n\t\t}\r\n\t\tthis.scannedFrozen = [];\r\n\t\tthis.scannedFrozenSchemas = [];\r\n\t}\r\n\r\n\tif (error || errorCount !== this.errors.length) {\r\n\t\twhile ((dataPathParts && dataPathParts.length) || (schemaPathParts && schemaPathParts.length)) {\r\n\t\t\tvar dataPart = (dataPathParts && dataPathParts.length) ? \"\" + dataPathParts.pop() : null;\r\n\t\t\tvar schemaPart = (schemaPathParts && schemaPathParts.length) ? \"\" + schemaPathParts.pop() : null;\r\n\t\t\tif (error) {\r\n\t\t\t\terror = error.prefixWith(dataPart, schemaPart);\r\n\t\t\t}\r\n\t\t\tthis.prefixErrors(errorCount, dataPart, schemaPart);\r\n\t\t}\r\n\t}\r\n\r\n\tif (scannedFrozenSchemaIndex !== null) {\r\n\t\tthis.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = this.errors.slice(startErrorCount);\r\n\t} else if (scannedSchemasIndex !== null) {\r\n\t\tdata[this.validationErrorsKey][scannedSchemasIndex] = this.errors.slice(startErrorCount);\r\n\t}\r\n\r\n\treturn this.handleError(error);\r\n};\r\nValidatorContext.prototype.validateFormat = function (data, schema) {\r\n\tif (typeof schema.format !== 'string' || !this.formatValidators[schema.format]) {\r\n\t\treturn null;\r\n\t}\r\n\tvar errorMessage = this.formatValidators[schema.format].call(null, data, schema);\r\n\tif (typeof errorMessage === 'string' || typeof errorMessage === 'number') {\r\n\t\treturn this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage}, '', '/format', null, data, schema);\r\n\t} else if (errorMessage && typeof errorMessage === 'object') {\r\n\t\treturn this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage.message || \"?\"}, errorMessage.dataPath || '', errorMessage.schemaPath || \"/format\", null, data, schema);\r\n\t}\r\n\treturn null;\r\n};\r\nValidatorContext.prototype.validateDefinedKeywords = function (data, schema, dataPointerPath) {\r\n\tfor (var key in this.definedKeywords) {\r\n\t\tif (typeof schema[key] === 'undefined') {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tvar validationFunctions = this.definedKeywords[key];\r\n\t\tfor (var i = 0; i < validationFunctions.length; i++) {\r\n\t\t\tvar func = validationFunctions[i];\r\n\t\t\tvar result = func(data, schema[key], schema, dataPointerPath);\r\n\t\t\tif (typeof result === 'string' || typeof result === 'number') {\r\n\t\t\t\treturn this.createError(ErrorCodes.KEYWORD_CUSTOM, {key: key, message: result}, '', '', null, data, schema).prefixWith(null, key);\r\n\t\t\t} else if (result && typeof result === 'object') {\r\n\t\t\t\tvar code = result.code;\r\n\t\t\t\tif (typeof code === 'string') {\r\n\t\t\t\t\tif (!ErrorCodes[code]) {\r\n\t\t\t\t\t\tthrow new Error('Undefined error code (use defineError): ' + code);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcode = ErrorCodes[code];\r\n\t\t\t\t} else if (typeof code !== 'number') {\r\n\t\t\t\t\tcode = ErrorCodes.KEYWORD_CUSTOM;\r\n\t\t\t\t}\r\n\t\t\t\tvar messageParams = (typeof result.message === 'object') ? result.message : {key: key, message: result.message || \"?\"};\r\n\t\t\t\tvar schemaPath = result.schemaPath || (\"/\" + key.replace(/~/g, '~0').replace(/\\//g, '~1'));\r\n\t\t\t\treturn this.createError(code, messageParams, result.dataPath || null, schemaPath, null, data, schema);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nfunction recursiveCompare(A, B) {\r\n\tif (A === B) {\r\n\t\treturn true;\r\n\t}\r\n\tif (A && B && typeof A === \"object\" && typeof B === \"object\") {\r\n\t\tif (Array.isArray(A) !== Array.isArray(B)) {\r\n\t\t\treturn false;\r\n\t\t} else if (Array.isArray(A)) {\r\n\t\t\tif (A.length !== B.length) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\tfor (var i = 0; i < A.length; i++) {\r\n\t\t\t\tif (!recursiveCompare(A[i], B[i])) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tvar key;\r\n\t\t\tfor (key in A) {\r\n\t\t\t\tif (B[key] === undefined && A[key] !== undefined) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tfor (key in B) {\r\n\t\t\t\tif (A[key] === undefined && B[key] !== undefined) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tfor (key in A) {\r\n\t\t\t\tif (!recursiveCompare(A[key], B[key])) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\treturn false;\r\n}\r\n\r\nValidatorContext.prototype.validateBasic = function validateBasic(data, schema, dataPointerPath) {\r\n\tvar error;\r\n\tif (error = this.validateType(data, schema, dataPointerPath)) {\r\n\t\treturn error.prefixWith(null, \"type\");\r\n\t}\r\n\tif (error = this.validateEnum(data, schema, dataPointerPath)) {\r\n\t\treturn error.prefixWith(null, \"type\");\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateType = function validateType(data, schema) {\r\n\tif (schema.type === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar dataType = typeof data;\r\n\tif (data === null) {\r\n\t\tdataType = \"null\";\r\n\t} else if (Array.isArray(data)) {\r\n\t\tdataType = \"array\";\r\n\t}\r\n\tvar allowedTypes = schema.type;\r\n\tif (!Array.isArray(allowedTypes)) {\r\n\t\tallowedTypes = [allowedTypes];\r\n\t}\r\n\r\n\tfor (var i = 0; i < allowedTypes.length; i++) {\r\n\t\tvar type = allowedTypes[i];\r\n\t\tif (type === dataType || (type === \"integer\" && dataType === \"number\" && (data % 1 === 0))) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\treturn this.createError(ErrorCodes.INVALID_TYPE, {type: dataType, expected: allowedTypes.join(\"/\")}, '', '', null, data, schema);\r\n};\r\n\r\nValidatorContext.prototype.validateEnum = function validateEnum(data, schema) {\r\n\tif (schema[\"enum\"] === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tfor (var i = 0; i < schema[\"enum\"].length; i++) {\r\n\t\tvar enumVal = schema[\"enum\"][i];\r\n\t\tif (recursiveCompare(data, enumVal)) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\treturn this.createError(ErrorCodes.ENUM_MISMATCH, {value: (typeof JSON !== 'undefined') ? JSON.stringify(data) : data}, '', '', null, data, schema);\r\n};\r\n\r\nValidatorContext.prototype.validateNumeric = function validateNumeric(data, schema, dataPointerPath) {\r\n\treturn this.validateMultipleOf(data, schema, dataPointerPath)\r\n\t\t|| this.validateMinMax(data, schema, dataPointerPath)\r\n\t\t|| this.validateNaN(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nvar CLOSE_ENOUGH_LOW = Math.pow(2, -51);\r\nvar CLOSE_ENOUGH_HIGH = 1 - CLOSE_ENOUGH_LOW;\r\nValidatorContext.prototype.validateMultipleOf = function validateMultipleOf(data, schema) {\r\n\tvar multipleOf = schema.multipleOf || schema.divisibleBy;\r\n\tif (multipleOf === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tif (typeof data === \"number\") {\r\n\t\tvar remainder = (data/multipleOf)%1;\r\n\t\tif (remainder >= CLOSE_ENOUGH_LOW && remainder < CLOSE_ENOUGH_HIGH) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MULTIPLE_OF, {value: data, multipleOf: multipleOf}, '', '', null, data, schema);\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateMinMax = function validateMinMax(data, schema) {\r\n\tif (typeof data !== \"number\") {\r\n\t\treturn null;\r\n\t}\r\n\tif (schema.minimum !== undefined) {\r\n\t\tif (data < schema.minimum) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MINIMUM, {value: data, minimum: schema.minimum}, '', '/minimum', null, data, schema);\r\n\t\t}\r\n\t\tif (schema.exclusiveMinimum && data === schema.minimum) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MINIMUM_EXCLUSIVE, {value: data, minimum: schema.minimum}, '', '/exclusiveMinimum', null, data, schema);\r\n\t\t}\r\n\t}\r\n\tif (schema.maximum !== undefined) {\r\n\t\tif (data > schema.maximum) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MAXIMUM, {value: data, maximum: schema.maximum}, '', '/maximum', null, data, schema);\r\n\t\t}\r\n\t\tif (schema.exclusiveMaximum && data === schema.maximum) {\r\n\t\t\treturn this.createError(ErrorCodes.NUMBER_MAXIMUM_EXCLUSIVE, {value: data, maximum: schema.maximum}, '', '/exclusiveMaximum', null, data, schema);\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateNaN = function validateNaN(data, schema) {\r\n\tif (typeof data !== \"number\") {\r\n\t\treturn null;\r\n\t}\r\n\tif (isNaN(data) === true || data === Infinity || data === -Infinity) {\r\n\t\treturn this.createError(ErrorCodes.NUMBER_NOT_A_NUMBER, {value: data}, '', '/type', null, data, schema);\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateString = function validateString(data, schema, dataPointerPath) {\r\n\treturn this.validateStringLength(data, schema, dataPointerPath)\r\n\t\t|| this.validateStringPattern(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nValidatorContext.prototype.validateStringLength = function validateStringLength(data, schema) {\r\n\tif (typeof data !== \"string\") {\r\n\t\treturn null;\r\n\t}\r\n\tif (schema.minLength !== undefined) {\r\n\t\tif (data.length < schema.minLength) {\r\n\t\t\treturn this.createError(ErrorCodes.STRING_LENGTH_SHORT, {length: data.length, minimum: schema.minLength}, '', '/minLength', null, data, schema);\r\n\t\t}\r\n\t}\r\n\tif (schema.maxLength !== undefined) {\r\n\t\tif (data.length > schema.maxLength) {\r\n\t\t\treturn this.createError(ErrorCodes.STRING_LENGTH_LONG, {length: data.length, maximum: schema.maxLength}, '', '/maxLength', null, data, schema);\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateStringPattern = function validateStringPattern(data, schema) {\r\n\tif (typeof data !== \"string\" || (typeof schema.pattern !== \"string\" && !(schema.pattern instanceof RegExp))) {\r\n\t\treturn null;\r\n\t}\r\n\tvar regexp;\r\n\tif (schema.pattern instanceof RegExp) {\r\n\t regexp = schema.pattern;\r\n\t}\r\n\telse {\r\n\t var body, flags = '';\r\n\t // Check for regular expression literals\r\n\t // @see http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.5\r\n\t var literal = schema.pattern.match(/^\\/(.+)\\/([img]*)$/);\r\n\t if (literal) {\r\n\t body = literal[1];\r\n\t flags = literal[2];\r\n\t }\r\n\t else {\r\n\t body = schema.pattern;\r\n\t }\r\n\t regexp = new RegExp(body, flags);\r\n\t}\r\n\tif (!regexp.test(data)) {\r\n\t\treturn this.createError(ErrorCodes.STRING_PATTERN, {pattern: schema.pattern}, '', '/pattern', null, data, schema);\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateArray = function validateArray(data, schema, dataPointerPath) {\r\n\tif (!Array.isArray(data)) {\r\n\t\treturn null;\r\n\t}\r\n\treturn this.validateArrayLength(data, schema, dataPointerPath)\r\n\t\t|| this.validateArrayUniqueItems(data, schema, dataPointerPath)\r\n\t\t|| this.validateArrayItems(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nValidatorContext.prototype.validateArrayLength = function validateArrayLength(data, schema) {\r\n\tvar error;\r\n\tif (schema.minItems !== undefined) {\r\n\t\tif (data.length < schema.minItems) {\r\n\t\t\terror = this.createError(ErrorCodes.ARRAY_LENGTH_SHORT, {length: data.length, minimum: schema.minItems}, '', '/minItems', null, data, schema);\r\n\t\t\tif (this.handleError(error)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tif (schema.maxItems !== undefined) {\r\n\t\tif (data.length > schema.maxItems) {\r\n\t\t\terror = this.createError(ErrorCodes.ARRAY_LENGTH_LONG, {length: data.length, maximum: schema.maxItems}, '', '/maxItems', null, data, schema);\r\n\t\t\tif (this.handleError(error)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateArrayUniqueItems = function validateArrayUniqueItems(data, schema) {\r\n\tif (schema.uniqueItems) {\r\n\t\tfor (var i = 0; i < data.length; i++) {\r\n\t\t\tfor (var j = i + 1; j < data.length; j++) {\r\n\t\t\t\tif (recursiveCompare(data[i], data[j])) {\r\n\t\t\t\t\tvar error = this.createError(ErrorCodes.ARRAY_UNIQUE, {match1: i, match2: j}, '', '/uniqueItems', null, data, schema);\r\n\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateArrayItems = function validateArrayItems(data, schema, dataPointerPath) {\r\n\tif (schema.items === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar error, i;\r\n\tif (Array.isArray(schema.items)) {\r\n\t\tfor (i = 0; i < data.length; i++) {\r\n\t\t\tif (i < schema.items.length) {\r\n\t\t\t\tif (error = this.validateAll(data[i], schema.items[i], [i], [\"items\", i], dataPointerPath + \"/\" + i)) {\r\n\t\t\t\t\treturn error;\r\n\t\t\t\t}\r\n\t\t\t} else if (schema.additionalItems !== undefined) {\r\n\t\t\t\tif (typeof schema.additionalItems === \"boolean\") {\r\n\t\t\t\t\tif (!schema.additionalItems) {\r\n\t\t\t\t\t\terror = (this.createError(ErrorCodes.ARRAY_ADDITIONAL_ITEMS, {}, '/' + i, '/additionalItems', null, data, schema));\r\n\t\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (error = this.validateAll(data[i], schema.additionalItems, [i], [\"additionalItems\"], dataPointerPath + \"/\" + i)) {\r\n\t\t\t\t\treturn error;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t} else {\r\n\t\tfor (i = 0; i < data.length; i++) {\r\n\t\t\tif (error = this.validateAll(data[i], schema.items, [i], [\"items\"], dataPointerPath + \"/\" + i)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateObject = function validateObject(data, schema, dataPointerPath) {\r\n\tif (typeof data !== \"object\" || data === null || Array.isArray(data)) {\r\n\t\treturn null;\r\n\t}\r\n\treturn this.validateObjectMinMaxProperties(data, schema, dataPointerPath)\r\n\t\t|| this.validateObjectRequiredProperties(data, schema, dataPointerPath)\r\n\t\t|| this.validateObjectProperties(data, schema, dataPointerPath)\r\n\t\t|| this.validateObjectDependencies(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nValidatorContext.prototype.validateObjectMinMaxProperties = function validateObjectMinMaxProperties(data, schema) {\r\n\tvar keys = Object.keys(data);\r\n\tvar error;\r\n\tif (schema.minProperties !== undefined) {\r\n\t\tif (keys.length < schema.minProperties) {\r\n\t\t\terror = this.createError(ErrorCodes.OBJECT_PROPERTIES_MINIMUM, {propertyCount: keys.length, minimum: schema.minProperties}, '', '/minProperties', null, data, schema);\r\n\t\t\tif (this.handleError(error)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tif (schema.maxProperties !== undefined) {\r\n\t\tif (keys.length > schema.maxProperties) {\r\n\t\t\terror = this.createError(ErrorCodes.OBJECT_PROPERTIES_MAXIMUM, {propertyCount: keys.length, maximum: schema.maxProperties}, '', '/maxProperties', null, data, schema);\r\n\t\t\tif (this.handleError(error)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateObjectRequiredProperties = function validateObjectRequiredProperties(data, schema) {\r\n\tif (schema.required !== undefined) {\r\n\t\tfor (var i = 0; i < schema.required.length; i++) {\r\n\t\t\tvar key = schema.required[i];\r\n\t\t\tif (data[key] === undefined) {\r\n\t\t\t\tvar error = this.createError(ErrorCodes.OBJECT_REQUIRED, {key: key}, '', '/required/' + i, null, data, schema);\r\n\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\treturn error;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateObjectProperties = function validateObjectProperties(data, schema, dataPointerPath) {\r\n\tvar error;\r\n\tfor (var key in data) {\r\n\t\tvar keyPointerPath = dataPointerPath + \"/\" + key.replace(/~/g, '~0').replace(/\\//g, '~1');\r\n\t\tvar foundMatch = false;\r\n\t\tif (schema.properties !== undefined && schema.properties[key] !== undefined) {\r\n\t\t\tfoundMatch = true;\r\n\t\t\tif (error = this.validateAll(data[key], schema.properties[key], [key], [\"properties\", key], keyPointerPath)) {\r\n\t\t\t\treturn error;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (schema.patternProperties !== undefined) {\r\n\t\t\tfor (var patternKey in schema.patternProperties) {\r\n\t\t\t\tvar regexp = new RegExp(patternKey);\r\n\t\t\t\tif (regexp.test(key)) {\r\n\t\t\t\t\tfoundMatch = true;\r\n\t\t\t\t\tif (error = this.validateAll(data[key], schema.patternProperties[patternKey], [key], [\"patternProperties\", patternKey], keyPointerPath)) {\r\n\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (!foundMatch) {\r\n\t\t\tif (schema.additionalProperties !== undefined) {\r\n\t\t\t\tif (this.trackUnknownProperties) {\r\n\t\t\t\t\tthis.knownPropertyPaths[keyPointerPath] = true;\r\n\t\t\t\t\tdelete this.unknownPropertyPaths[keyPointerPath];\r\n\t\t\t\t}\r\n\t\t\t\tif (typeof schema.additionalProperties === \"boolean\") {\r\n\t\t\t\t\tif (!schema.additionalProperties) {\r\n\t\t\t\t\t\terror = this.createError(ErrorCodes.OBJECT_ADDITIONAL_PROPERTIES, {key: key}, '', '/additionalProperties', null, data, schema).prefixWith(key, null);\r\n\t\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (error = this.validateAll(data[key], schema.additionalProperties, [key], [\"additionalProperties\"], keyPointerPath)) {\r\n\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else if (this.trackUnknownProperties && !this.knownPropertyPaths[keyPointerPath]) {\r\n\t\t\t\tthis.unknownPropertyPaths[keyPointerPath] = true;\r\n\t\t\t}\r\n\t\t} else if (this.trackUnknownProperties) {\r\n\t\t\tthis.knownPropertyPaths[keyPointerPath] = true;\r\n\t\t\tdelete this.unknownPropertyPaths[keyPointerPath];\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateObjectDependencies = function validateObjectDependencies(data, schema, dataPointerPath) {\r\n\tvar error;\r\n\tif (schema.dependencies !== undefined) {\r\n\t\tfor (var depKey in schema.dependencies) {\r\n\t\t\tif (data[depKey] !== undefined) {\r\n\t\t\t\tvar dep = schema.dependencies[depKey];\r\n\t\t\t\tif (typeof dep === \"string\") {\r\n\t\t\t\t\tif (data[dep] === undefined) {\r\n\t\t\t\t\t\terror = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: dep}, '', '', null, data, schema).prefixWith(null, depKey).prefixWith(null, \"dependencies\");\r\n\t\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else if (Array.isArray(dep)) {\r\n\t\t\t\t\tfor (var i = 0; i < dep.length; i++) {\r\n\t\t\t\t\t\tvar requiredKey = dep[i];\r\n\t\t\t\t\t\tif (data[requiredKey] === undefined) {\r\n\t\t\t\t\t\t\terror = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: requiredKey}, '', '/' + i, null, data, schema).prefixWith(null, depKey).prefixWith(null, \"dependencies\");\r\n\t\t\t\t\t\t\tif (this.handleError(error)) {\r\n\t\t\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (error = this.validateAll(data, dep, [], [\"dependencies\", depKey], dataPointerPath)) {\r\n\t\t\t\t\t\treturn error;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateCombinations = function validateCombinations(data, schema, dataPointerPath) {\r\n\treturn this.validateAllOf(data, schema, dataPointerPath)\r\n\t\t|| this.validateAnyOf(data, schema, dataPointerPath)\r\n\t\t|| this.validateOneOf(data, schema, dataPointerPath)\r\n\t\t|| this.validateNot(data, schema, dataPointerPath)\r\n\t\t|| null;\r\n};\r\n\r\nValidatorContext.prototype.validateAllOf = function validateAllOf(data, schema, dataPointerPath) {\r\n\tif (schema.allOf === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar error;\r\n\tfor (var i = 0; i < schema.allOf.length; i++) {\r\n\t\tvar subSchema = schema.allOf[i];\r\n\t\tif (error = this.validateAll(data, subSchema, [], [\"allOf\", i], dataPointerPath)) {\r\n\t\t\treturn error;\r\n\t\t}\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateAnyOf = function validateAnyOf(data, schema, dataPointerPath) {\r\n\tif (schema.anyOf === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar errors = [];\r\n\tvar startErrorCount = this.errors.length;\r\n\tvar oldUnknownPropertyPaths, oldKnownPropertyPaths;\r\n\tif (this.trackUnknownProperties) {\r\n\t\toldUnknownPropertyPaths = this.unknownPropertyPaths;\r\n\t\toldKnownPropertyPaths = this.knownPropertyPaths;\r\n\t}\r\n\tvar errorAtEnd = true;\r\n\tfor (var i = 0; i < schema.anyOf.length; i++) {\r\n\t\tif (this.trackUnknownProperties) {\r\n\t\t\tthis.unknownPropertyPaths = {};\r\n\t\t\tthis.knownPropertyPaths = {};\r\n\t\t}\r\n\t\tvar subSchema = schema.anyOf[i];\r\n\r\n\t\tvar errorCount = this.errors.length;\r\n\t\tvar error = this.validateAll(data, subSchema, [], [\"anyOf\", i], dataPointerPath);\r\n\r\n\t\tif (error === null && errorCount === this.errors.length) {\r\n\t\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\r\n\t\t\tif (this.trackUnknownProperties) {\r\n\t\t\t\tfor (var knownKey in this.knownPropertyPaths) {\r\n\t\t\t\t\toldKnownPropertyPaths[knownKey] = true;\r\n\t\t\t\t\tdelete oldUnknownPropertyPaths[knownKey];\r\n\t\t\t\t}\r\n\t\t\t\tfor (var unknownKey in this.unknownPropertyPaths) {\r\n\t\t\t\t\tif (!oldKnownPropertyPaths[unknownKey]) {\r\n\t\t\t\t\t\toldUnknownPropertyPaths[unknownKey] = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t// We need to continue looping so we catch all the property definitions, but we don't want to return an error\r\n\t\t\t\terrorAtEnd = false;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\tif (error) {\r\n\t\t\terrors.push(error.prefixWith(null, \"\" + i).prefixWith(null, \"anyOf\"));\r\n\t\t}\r\n\t}\r\n\tif (this.trackUnknownProperties) {\r\n\t\tthis.unknownPropertyPaths = oldUnknownPropertyPaths;\r\n\t\tthis.knownPropertyPaths = oldKnownPropertyPaths;\r\n\t}\r\n\tif (errorAtEnd) {\r\n\t\terrors = errors.concat(this.errors.slice(startErrorCount));\r\n\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\t\treturn this.createError(ErrorCodes.ANY_OF_MISSING, {}, \"\", \"/anyOf\", errors, data, schema);\r\n\t}\r\n};\r\n\r\nValidatorContext.prototype.validateOneOf = function validateOneOf(data, schema, dataPointerPath) {\r\n\tif (schema.oneOf === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar validIndex = null;\r\n\tvar errors = [];\r\n\tvar startErrorCount = this.errors.length;\r\n\tvar oldUnknownPropertyPaths, oldKnownPropertyPaths;\r\n\tif (this.trackUnknownProperties) {\r\n\t\toldUnknownPropertyPaths = this.unknownPropertyPaths;\r\n\t\toldKnownPropertyPaths = this.knownPropertyPaths;\r\n\t}\r\n\tfor (var i = 0; i < schema.oneOf.length; i++) {\r\n\t\tif (this.trackUnknownProperties) {\r\n\t\t\tthis.unknownPropertyPaths = {};\r\n\t\t\tthis.knownPropertyPaths = {};\r\n\t\t}\r\n\t\tvar subSchema = schema.oneOf[i];\r\n\r\n\t\tvar errorCount = this.errors.length;\r\n\t\tvar error = this.validateAll(data, subSchema, [], [\"oneOf\", i], dataPointerPath);\r\n\r\n\t\tif (error === null && errorCount === this.errors.length) {\r\n\t\t\tif (validIndex === null) {\r\n\t\t\t\tvalidIndex = i;\r\n\t\t\t} else {\r\n\t\t\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\t\t\t\treturn this.createError(ErrorCodes.ONE_OF_MULTIPLE, {index1: validIndex, index2: i}, \"\", \"/oneOf\", null, data, schema);\r\n\t\t\t}\r\n\t\t\tif (this.trackUnknownProperties) {\r\n\t\t\t\tfor (var knownKey in this.knownPropertyPaths) {\r\n\t\t\t\t\toldKnownPropertyPaths[knownKey] = true;\r\n\t\t\t\t\tdelete oldUnknownPropertyPaths[knownKey];\r\n\t\t\t\t}\r\n\t\t\t\tfor (var unknownKey in this.unknownPropertyPaths) {\r\n\t\t\t\t\tif (!oldKnownPropertyPaths[unknownKey]) {\r\n\t\t\t\t\t\toldUnknownPropertyPaths[unknownKey] = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else if (error) {\r\n\t\t\terrors.push(error);\r\n\t\t}\r\n\t}\r\n\tif (this.trackUnknownProperties) {\r\n\t\tthis.unknownPropertyPaths = oldUnknownPropertyPaths;\r\n\t\tthis.knownPropertyPaths = oldKnownPropertyPaths;\r\n\t}\r\n\tif (validIndex === null) {\r\n\t\terrors = errors.concat(this.errors.slice(startErrorCount));\r\n\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\t\treturn this.createError(ErrorCodes.ONE_OF_MISSING, {}, \"\", \"/oneOf\", errors, data, schema);\r\n\t} else {\r\n\t\tthis.errors = this.errors.slice(0, startErrorCount);\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateNot = function validateNot(data, schema, dataPointerPath) {\r\n\tif (schema.not === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\tvar oldErrorCount = this.errors.length;\r\n\tvar oldUnknownPropertyPaths, oldKnownPropertyPaths;\r\n\tif (this.trackUnknownProperties) {\r\n\t\toldUnknownPropertyPaths = this.unknownPropertyPaths;\r\n\t\toldKnownPropertyPaths = this.knownPropertyPaths;\r\n\t\tthis.unknownPropertyPaths = {};\r\n\t\tthis.knownPropertyPaths = {};\r\n\t}\r\n\tvar error = this.validateAll(data, schema.not, null, null, dataPointerPath);\r\n\tvar notErrors = this.errors.slice(oldErrorCount);\r\n\tthis.errors = this.errors.slice(0, oldErrorCount);\r\n\tif (this.trackUnknownProperties) {\r\n\t\tthis.unknownPropertyPaths = oldUnknownPropertyPaths;\r\n\t\tthis.knownPropertyPaths = oldKnownPropertyPaths;\r\n\t}\r\n\tif (error === null && notErrors.length === 0) {\r\n\t\treturn this.createError(ErrorCodes.NOT_PASSED, {}, \"\", \"/not\", null, data, schema);\r\n\t}\r\n\treturn null;\r\n};\r\n\r\nValidatorContext.prototype.validateHypermedia = function validateCombinations(data, schema, dataPointerPath) {\r\n\tif (!schema.links) {\r\n\t\treturn null;\r\n\t}\r\n\tvar error;\r\n\tfor (var i = 0; i < schema.links.length; i++) {\r\n\t\tvar ldo = schema.links[i];\r\n\t\tif (ldo.rel === \"describedby\") {\r\n\t\t\tvar template = new UriTemplate(ldo.href);\r\n\t\t\tvar allPresent = true;\r\n\t\t\tfor (var j = 0; j < template.varNames.length; j++) {\r\n\t\t\t\tif (!(template.varNames[j] in data)) {\r\n\t\t\t\t\tallPresent = false;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (allPresent) {\r\n\t\t\t\tvar schemaUrl = template.fillFromObject(data);\r\n\t\t\t\tvar subSchema = {\"$ref\": schemaUrl};\r\n\t\t\t\tif (error = this.validateAll(data, subSchema, [], [\"links\", i], dataPointerPath)) {\r\n\t\t\t\t\treturn error;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n};\r\n\r\n// parseURI() and resolveUrl() are from https://gist.github.com/1088850\r\n// - released as public domain by author (\"Yaffle\") - see comments on gist\r\n\r\nfunction parseURI(url) {\r\n\tvar m = String(url).replace(/^\\s+|\\s+$/g, '').match(/^([^:\\/?#]+:)?(\\/\\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\\/?#]*)(?::(\\d*))?))?([^?#]*)(\\?[^#]*)?(#[\\s\\S]*)?/);\r\n\t// authority = '//' + user + ':' + pass '@' + hostname + ':' port\r\n\treturn (m ? {\r\n\t\thref : m[0] || '',\r\n\t\tprotocol : m[1] || '',\r\n\t\tauthority: m[2] || '',\r\n\t\thost : m[3] || '',\r\n\t\thostname : m[4] || '',\r\n\t\tport : m[5] || '',\r\n\t\tpathname : m[6] || '',\r\n\t\tsearch : m[7] || '',\r\n\t\thash : m[8] || ''\r\n\t} : null);\r\n}\r\n\r\nfunction resolveUrl(base, href) {// RFC 3986\r\n\r\n\tfunction removeDotSegments(input) {\r\n\t\tvar output = [];\r\n\t\tinput.replace(/^(\\.\\.?(\\/|$))+/, '')\r\n\t\t\t.replace(/\\/(\\.(\\/|$))+/g, '/')\r\n\t\t\t.replace(/\\/\\.\\.$/, '/../')\r\n\t\t\t.replace(/\\/?[^\\/]*/g, function (p) {\r\n\t\t\t\tif (p === '/..') {\r\n\t\t\t\t\toutput.pop();\r\n\t\t\t\t} else {\r\n\t\t\t\t\toutput.push(p);\r\n\t\t\t\t}\r\n\t\t});\r\n\t\treturn output.join('').replace(/^\\//, input.charAt(0) === '/' ? '/' : '');\r\n\t}\r\n\r\n\thref = parseURI(href || '');\r\n\tbase = parseURI(base || '');\r\n\r\n\treturn !href || !base ? null : (href.protocol || base.protocol) +\r\n\t\t(href.protocol || href.authority ? href.authority : base.authority) +\r\n\t\tremoveDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +\r\n\t\t(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +\r\n\t\thref.hash;\r\n}\r\n\r\nfunction getDocumentUri(uri) {\r\n\treturn uri.split('#')[0];\r\n}\r\nfunction normSchema(schema, baseUri) {\r\n\tif (schema && typeof schema === \"object\") {\r\n\t\tif (baseUri === undefined) {\r\n\t\t\tbaseUri = schema.id;\r\n\t\t} else if (typeof schema.id === \"string\") {\r\n\t\t\tbaseUri = resolveUrl(baseUri, schema.id);\r\n\t\t\tschema.id = baseUri;\r\n\t\t}\r\n\t\tif (Array.isArray(schema)) {\r\n\t\t\tfor (var i = 0; i < schema.length; i++) {\r\n\t\t\t\tnormSchema(schema[i], baseUri);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (typeof schema['$ref'] === \"string\") {\r\n\t\t\t\tschema['$ref'] = resolveUrl(baseUri, schema['$ref']);\r\n\t\t\t}\r\n\t\t\tfor (var key in schema) {\r\n\t\t\t\tif (key !== \"enum\") {\r\n\t\t\t\t\tnormSchema(schema[key], baseUri);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction defaultErrorReporter(language) {\r\n\tlanguage = language || 'en';\r\n\r\n\tvar errorMessages = languages[language];\r\n\r\n\treturn function (error) {\r\n\t\tvar messageTemplate = errorMessages[error.code] || ErrorMessagesDefault[error.code];\r\n\t\tif (typeof messageTemplate !== 'string') {\r\n\t\t\treturn \"Unknown error code \" + error.code + \": \" + JSON.stringify(error.messageParams);\r\n\t\t}\r\n\t\tvar messageParams = error.params;\r\n\t\t// Adapted from Crockford's supplant()\r\n\t\treturn messageTemplate.replace(/\\{([^{}]*)\\}/g, function (whole, varName) {\r\n\t\t\tvar subValue = messageParams[varName];\r\n\t\t\treturn typeof subValue === 'string' || typeof subValue === 'number' ? subValue : whole;\r\n\t\t});\r\n\t};\r\n}\r\n\r\nvar ErrorCodes = {\r\n\tINVALID_TYPE: 0,\r\n\tENUM_MISMATCH: 1,\r\n\tANY_OF_MISSING: 10,\r\n\tONE_OF_MISSING: 11,\r\n\tONE_OF_MULTIPLE: 12,\r\n\tNOT_PASSED: 13,\r\n\t// Numeric errors\r\n\tNUMBER_MULTIPLE_OF: 100,\r\n\tNUMBER_MINIMUM: 101,\r\n\tNUMBER_MINIMUM_EXCLUSIVE: 102,\r\n\tNUMBER_MAXIMUM: 103,\r\n\tNUMBER_MAXIMUM_EXCLUSIVE: 104,\r\n\tNUMBER_NOT_A_NUMBER: 105,\r\n\t// String errors\r\n\tSTRING_LENGTH_SHORT: 200,\r\n\tSTRING_LENGTH_LONG: 201,\r\n\tSTRING_PATTERN: 202,\r\n\t// Object errors\r\n\tOBJECT_PROPERTIES_MINIMUM: 300,\r\n\tOBJECT_PROPERTIES_MAXIMUM: 301,\r\n\tOBJECT_REQUIRED: 302,\r\n\tOBJECT_ADDITIONAL_PROPERTIES: 303,\r\n\tOBJECT_DEPENDENCY_KEY: 304,\r\n\t// Array errors\r\n\tARRAY_LENGTH_SHORT: 400,\r\n\tARRAY_LENGTH_LONG: 401,\r\n\tARRAY_UNIQUE: 402,\r\n\tARRAY_ADDITIONAL_ITEMS: 403,\r\n\t// Custom/user-defined errors\r\n\tFORMAT_CUSTOM: 500,\r\n\tKEYWORD_CUSTOM: 501,\r\n\t// Schema structure\r\n\tCIRCULAR_REFERENCE: 600,\r\n\t// Non-standard validation options\r\n\tUNKNOWN_PROPERTY: 1000\r\n};\r\nvar ErrorCodeLookup = {};\r\nfor (var key in ErrorCodes) {\r\n\tErrorCodeLookup[ErrorCodes[key]] = key;\r\n}\r\nvar ErrorMessagesDefault = {\r\n\tINVALID_TYPE: \"Invalid type: {type} (expected {expected})\",\r\n\tENUM_MISMATCH: \"No enum match for: {value}\",\r\n\tANY_OF_MISSING: \"Data does not match any schemas from \\\"anyOf\\\"\",\r\n\tONE_OF_MISSING: \"Data does not match any schemas from \\\"oneOf\\\"\",\r\n\tONE_OF_MULTIPLE: \"Data is valid against more than one schema from \\\"oneOf\\\": indices {index1} and {index2}\",\r\n\tNOT_PASSED: \"Data matches schema from \\\"not\\\"\",\r\n\t// Numeric errors\r\n\tNUMBER_MULTIPLE_OF: \"Value {value} is not a multiple of {multipleOf}\",\r\n\tNUMBER_MINIMUM: \"Value {value} is less than minimum {minimum}\",\r\n\tNUMBER_MINIMUM_EXCLUSIVE: \"Value {value} is equal to exclusive minimum {minimum}\",\r\n\tNUMBER_MAXIMUM: \"Value {value} is greater than maximum {maximum}\",\r\n\tNUMBER_MAXIMUM_EXCLUSIVE: \"Value {value} is equal to exclusive maximum {maximum}\",\r\n\tNUMBER_NOT_A_NUMBER: \"Value {value} is not a valid number\",\r\n\t// String errors\r\n\tSTRING_LENGTH_SHORT: \"String is too short ({length} chars), minimum {minimum}\",\r\n\tSTRING_LENGTH_LONG: \"String is too long ({length} chars), maximum {maximum}\",\r\n\tSTRING_PATTERN: \"String does not match pattern: {pattern}\",\r\n\t// Object errors\r\n\tOBJECT_PROPERTIES_MINIMUM: \"Too few properties defined ({propertyCount}), minimum {minimum}\",\r\n\tOBJECT_PROPERTIES_MAXIMUM: \"Too many properties defined ({propertyCount}), maximum {maximum}\",\r\n\tOBJECT_REQUIRED: \"Missing required property: {key}\",\r\n\tOBJECT_ADDITIONAL_PROPERTIES: \"Additional properties not allowed\",\r\n\tOBJECT_DEPENDENCY_KEY: \"Dependency failed - key must exist: {missing} (due to key: {key})\",\r\n\t// Array errors\r\n\tARRAY_LENGTH_SHORT: \"Array is too short ({length}), minimum {minimum}\",\r\n\tARRAY_LENGTH_LONG: \"Array is too long ({length}), maximum {maximum}\",\r\n\tARRAY_UNIQUE: \"Array items are not unique (indices {match1} and {match2})\",\r\n\tARRAY_ADDITIONAL_ITEMS: \"Additional items not allowed\",\r\n\t// Format errors\r\n\tFORMAT_CUSTOM: \"Format validation failed ({message})\",\r\n\tKEYWORD_CUSTOM: \"Keyword failed: {key} ({message})\",\r\n\t// Schema structure\r\n\tCIRCULAR_REFERENCE: \"Circular $refs: {urls}\",\r\n\t// Non-standard validation options\r\n\tUNKNOWN_PROPERTY: \"Unknown property (not in schema)\"\r\n};\r\n\r\nfunction ValidationError(code, params, dataPath, schemaPath, subErrors) {\r\n\tError.call(this);\r\n\tif (code === undefined) {\r\n\t\tthrow new Error (\"No error code supplied: \" + schemaPath);\r\n\t}\r\n\tthis.message = '';\r\n\tthis.params = params;\r\n\tthis.code = code;\r\n\tthis.dataPath = dataPath || \"\";\r\n\tthis.schemaPath = schemaPath || \"\";\r\n\tthis.subErrors = subErrors || null;\r\n\r\n\tvar err = new Error(this.message);\r\n\tthis.stack = err.stack || err.stacktrace;\r\n\tif (!this.stack) {\r\n\t\ttry {\r\n\t\t\tthrow err;\r\n\t\t}\r\n\t\tcatch(err) {\r\n\t\t\tthis.stack = err.stack || err.stacktrace;\r\n\t\t}\r\n\t}\r\n}\r\nValidationError.prototype = Object.create(Error.prototype);\r\nValidationError.prototype.constructor = ValidationError;\r\nValidationError.prototype.name = 'ValidationError';\r\n\r\nValidationError.prototype.prefixWith = function (dataPrefix, schemaPrefix) {\r\n\tif (dataPrefix !== null) {\r\n\t\tdataPrefix = dataPrefix.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\r\n\t\tthis.dataPath = \"/\" + dataPrefix + this.dataPath;\r\n\t}\r\n\tif (schemaPrefix !== null) {\r\n\t\tschemaPrefix = schemaPrefix.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\r\n\t\tthis.schemaPath = \"/\" + schemaPrefix + this.schemaPath;\r\n\t}\r\n\tif (this.subErrors !== null) {\r\n\t\tfor (var i = 0; i < this.subErrors.length; i++) {\r\n\t\t\tthis.subErrors[i].prefixWith(dataPrefix, schemaPrefix);\r\n\t\t}\r\n\t}\r\n\treturn this;\r\n};\r\n\r\nfunction isTrustedUrl(baseUrl, testUrl) {\r\n\tif(testUrl.substring(0, baseUrl.length) === baseUrl){\r\n\t\tvar remainder = testUrl.substring(baseUrl.length);\r\n\t\tif ((testUrl.length > 0 && testUrl.charAt(baseUrl.length - 1) === \"/\")\r\n\t\t\t|| remainder.charAt(0) === \"#\"\r\n\t\t\t|| remainder.charAt(0) === \"?\") {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t}\r\n\treturn false;\r\n}\r\n\r\nvar languages = {};\r\nfunction createApi(language) {\r\n\tvar globalContext = new ValidatorContext();\r\n\tvar currentLanguage;\r\n\tvar customErrorReporter;\r\n\tvar api = {\r\n\t\tsetErrorReporter: function (reporter) {\r\n\t\t\tif (typeof reporter === 'string') {\r\n\t\t\t\treturn this.language(reporter);\r\n\t\t\t}\r\n\t\t\tcustomErrorReporter = reporter;\r\n\t\t\treturn true;\r\n\t\t},\r\n\t\taddFormat: function () {\r\n\t\t\tglobalContext.addFormat.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tlanguage: function (code) {\r\n\t\t\tif (!code) {\r\n\t\t\t\treturn currentLanguage;\r\n\t\t\t}\r\n\t\t\tif (!languages[code]) {\r\n\t\t\t\tcode = code.split('-')[0]; // fall back to base language\r\n\t\t\t}\r\n\t\t\tif (languages[code]) {\r\n\t\t\t\tcurrentLanguage = code;\r\n\t\t\t\treturn code; // so you can tell if fall-back has happened\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t},\r\n\t\taddLanguage: function (code, messageMap) {\r\n\t\t\tvar key;\r\n\t\t\tfor (key in ErrorCodes) {\r\n\t\t\t\tif (messageMap[key] && !messageMap[ErrorCodes[key]]) {\r\n\t\t\t\t\tmessageMap[ErrorCodes[key]] = messageMap[key];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tvar rootCode = code.split('-')[0];\r\n\t\t\tif (!languages[rootCode]) { // use for base language if not yet defined\r\n\t\t\t\tlanguages[code] = messageMap;\r\n\t\t\t\tlanguages[rootCode] = messageMap;\r\n\t\t\t} else {\r\n\t\t\t\tlanguages[code] = Object.create(languages[rootCode]);\r\n\t\t\t\tfor (key in messageMap) {\r\n\t\t\t\t\tif (typeof languages[rootCode][key] === 'undefined') {\r\n\t\t\t\t\t\tlanguages[rootCode][key] = messageMap[key];\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlanguages[code][key] = messageMap[key];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn this;\r\n\t\t},\r\n\t\tfreshApi: function (language) {\r\n\t\t\tvar result = createApi();\r\n\t\t\tif (language) {\r\n\t\t\t\tresult.language(language);\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tvalidate: function (data, schema, checkRecursive, banUnknownProperties) {\r\n\t\t\tvar def = defaultErrorReporter(currentLanguage);\r\n\t\t\tvar errorReporter = customErrorReporter ? function (error, data, schema) {\r\n\t\t\t\treturn customErrorReporter(error, data, schema) || def(error, data, schema);\r\n\t\t\t} : def;\r\n\t\t\tvar context = new ValidatorContext(globalContext, false, errorReporter, checkRecursive, banUnknownProperties);\r\n\t\t\tif (typeof schema === \"string\") {\r\n\t\t\t\tschema = {\"$ref\": schema};\r\n\t\t\t}\r\n\t\t\tcontext.addSchema(\"\", schema);\r\n\t\t\tvar error = context.validateAll(data, schema, null, null, \"\");\r\n\t\t\tif (!error && banUnknownProperties) {\r\n\t\t\t\terror = context.banUnknownProperties(data, schema);\r\n\t\t\t}\r\n\t\t\tthis.error = error;\r\n\t\t\tthis.missing = context.missing;\r\n\t\t\tthis.valid = (error === null);\r\n\t\t\treturn this.valid;\r\n\t\t},\r\n\t\tvalidateResult: function () {\r\n\t\t\tvar result = {toString: function () {\r\n\t\t\t\treturn this.valid ? 'valid' : this.error.message;\r\n\t\t\t}};\r\n\t\t\tthis.validate.apply(result, arguments);\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\tvalidateMultiple: function (data, schema, checkRecursive, banUnknownProperties) {\r\n\t\t\tvar def = defaultErrorReporter(currentLanguage);\r\n\t\t\tvar errorReporter = customErrorReporter ? function (error, data, schema) {\r\n\t\t\t\treturn customErrorReporter(error, data, schema) || def(error, data, schema);\r\n\t\t\t} : def;\r\n\t\t\tvar context = new ValidatorContext(globalContext, true, errorReporter, checkRecursive, banUnknownProperties);\r\n\t\t\tif (typeof schema === \"string\") {\r\n\t\t\t\tschema = {\"$ref\": schema};\r\n\t\t\t}\r\n\t\t\tcontext.addSchema(\"\", schema);\r\n\t\t\tcontext.validateAll(data, schema, null, null, \"\");\r\n\t\t\tif (banUnknownProperties) {\r\n\t\t\t\tcontext.banUnknownProperties(data, schema);\r\n\t\t\t}\r\n\t\t\tvar result = {toString: function () {\r\n\t\t\t\treturn this.valid ? 'valid' : this.error.message;\r\n\t\t\t}};\r\n\t\t\tresult.errors = context.errors;\r\n\t\t\tresult.missing = context.missing;\r\n\t\t\tresult.valid = (result.errors.length === 0);\r\n\t\t\treturn result;\r\n\t\t},\r\n\t\taddSchema: function () {\r\n\t\t\treturn globalContext.addSchema.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tgetSchema: function () {\r\n\t\t\treturn globalContext.getSchema.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tgetSchemaMap: function () {\r\n\t\t\treturn globalContext.getSchemaMap.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tgetSchemaUris: function () {\r\n\t\t\treturn globalContext.getSchemaUris.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tgetMissingUris: function () {\r\n\t\t\treturn globalContext.getMissingUris.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tdropSchemas: function () {\r\n\t\t\tglobalContext.dropSchemas.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tdefineKeyword: function () {\r\n\t\t\tglobalContext.defineKeyword.apply(globalContext, arguments);\r\n\t\t},\r\n\t\tdefineError: function (codeName, codeNumber, defaultMessage) {\r\n\t\t\tif (typeof codeName !== 'string' || !/^[A-Z]+(_[A-Z]+)*$/.test(codeName)) {\r\n\t\t\t\tthrow new Error('Code name must be a string in UPPER_CASE_WITH_UNDERSCORES');\r\n\t\t\t}\r\n\t\t\tif (typeof codeNumber !== 'number' || codeNumber%1 !== 0 || codeNumber < 10000) {\r\n\t\t\t\tthrow new Error('Code number must be an integer > 10000');\r\n\t\t\t}\r\n\t\t\tif (typeof ErrorCodes[codeName] !== 'undefined') {\r\n\t\t\t\tthrow new Error('Error already defined: ' + codeName + ' as ' + ErrorCodes[codeName]);\r\n\t\t\t}\r\n\t\t\tif (typeof ErrorCodeLookup[codeNumber] !== 'undefined') {\r\n\t\t\t\tthrow new Error('Error code already used: ' + ErrorCodeLookup[codeNumber] + ' as ' + codeNumber);\r\n\t\t\t}\r\n\t\t\tErrorCodes[codeName] = codeNumber;\r\n\t\t\tErrorCodeLookup[codeNumber] = codeName;\r\n\t\t\tErrorMessagesDefault[codeName] = ErrorMessagesDefault[codeNumber] = defaultMessage;\r\n\t\t\tfor (var langCode in languages) {\r\n\t\t\t\tvar language = languages[langCode];\r\n\t\t\t\tif (language[codeName]) {\r\n\t\t\t\t\tlanguage[codeNumber] = language[codeNumber] || language[codeName];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\treset: function () {\r\n\t\t\tglobalContext.reset();\r\n\t\t\tthis.error = null;\r\n\t\t\tthis.missing = [];\r\n\t\t\tthis.valid = true;\r\n\t\t},\r\n\t\tmissing: [],\r\n\t\terror: null,\r\n\t\tvalid: true,\r\n\t\tnormSchema: normSchema,\r\n\t\tresolveUrl: resolveUrl,\r\n\t\tgetDocumentUri: getDocumentUri,\r\n\t\terrorCodes: ErrorCodes\r\n\t};\r\n\tapi.language(language || 'en');\r\n\treturn api;\r\n}\r\n\r\nvar tv4 = createApi();\r\ntv4.addLanguage('en-gb', ErrorMessagesDefault);\r\n\r\n//legacy property\r\ntv4.tv4 = tv4;\r\n\r\nreturn tv4; // used by _header.js to globalise.\r\n\r\n}));","import type { JsonSchemas } from './interfaces/json_schema';\n/**\n * - Manages and validates types of remoteStorage objects, using JSON-LD and\n * JSON Schema\n * - Adds schema declaration/validation methods to BaseClient instances.\n **/\nexport class BaseClientTypes {\n /**\n * -> \n */\n uris: { [key: string]: string } = {};\n\n /**\n * Contains schema objects of all types known to the BaseClient instance\n *\n * -> \n */\n schemas: JsonSchemas = {};\n\n /**\n * -> \n */\n aliases: { [key: string]: string } = {};\n\n /**\n * Called via public function BaseClient.declareType()\n *\n * @private\n */\n declare (moduleName: string, alias: string, uri: string, schema: tv4.JsonSchema): void {\n const fullAlias = moduleName + '/' + alias;\n\n if (schema.extends) {\n const parts = schema.extends.split('/');\n const extendedAlias = (parts.length === 1)\n ? moduleName + '/' + parts.shift()\n : parts.join('/');\n\n const extendedUri = this.uris[extendedAlias];\n if (!extendedUri) {\n throw \"Type '\" + fullAlias + \"' tries to extend unknown schema '\" + extendedAlias + \"'\";\n }\n schema.extends = this.schemas[extendedUri];\n }\n\n this.uris[fullAlias] = uri;\n this.aliases[uri] = fullAlias;\n this.schemas[uri] = schema;\n }\n\n resolveAlias (alias: string): string {\n return this.uris[alias];\n }\n\n getSchema (uri: string): tv4.JsonSchema {\n return this.schemas[uri];\n }\n\n inScope (moduleName: string): JsonSchemas {\n const ml = moduleName.length;\n const schemas = {};\n for (const alias in this.uris) {\n if (alias.substr(0, ml + 1) === moduleName + '/') {\n const uri = this.uris[alias];\n schemas[uri] = this.schemas[uri];\n }\n }\n return schemas;\n }\n}\n\nconst Types = new BaseClientTypes();\nexport default Types;\n","class SchemaNotFound extends Error {\n constructor(uri: string) {\n super();\n const error = new Error(\"Schema not found: \" + uri);\n error.name = \"SchemaNotFound\";\n return error;\n }\n}\n\nexport = SchemaNotFound;\n","/**\n * A cache which can propagate changes up to parent folders and generate new\n * revision ids for them. The generated revision id is consistent across\n * different sessions. The keys for the cache are case-insensitive.\n *\n * @param defaultValue {string} the value that is returned for all keys that\n * don't exist in the cache\n * @class\n */\n\nclass RevisionCache {\n defaultValue: string;\n\n private _itemsRev: { [key: string]: any } = {};\n private _storage: { [key: string]: string } = {};\n private _canPropagate = false;\n\n constructor(defaultValue: string) {\n this.defaultValue = defaultValue;\n this.activatePropagation();\n }\n\n\n /**\n * Get a value from the cache or defaultValue, if the key is not in the\n * cache\n */\n get(key: string): string {\n key = key.toLowerCase();\n let stored = this._storage[key];\n if (typeof stored === 'undefined') {\n stored = this.defaultValue;\n this._storage[key] = stored;\n }\n return stored;\n }\n\n /**\n * Set a value\n */\n set(key: string, value): unknown {\n key = key.toLowerCase();\n if (this._storage[key] === value) {\n return value;\n }\n this._storage[key] = value;\n if (!value) {\n delete this._itemsRev[key];\n }\n this._updateParentFolderItemRev(key, value);\n if (this._canPropagate) {\n this._propagate(key);\n }\n return value;\n }\n\n /**\n * Delete a value\n */\n delete(key: string): unknown {\n return this.set(key, null);\n }\n\n /**\n * Disables automatic update of folder revisions when a key value is updated\n */\n deactivatePropagation(): true {\n this._canPropagate = false;\n return true;\n }\n\n /**\n * Enables automatic update of folder revisions when a key value is updated\n * and refreshes the folder revision ids for entire tree.\n */\n activatePropagation(): true {\n if (this._canPropagate) {\n return true;\n }\n this._generateFolderRev(\"/\");\n this._canPropagate = true;\n return true;\n }\n\n /**\n * Returns a hash code for a string.\n */\n private _hashCode(str: string): number {\n let hash = 0;\n if (str.length === 0) {\n return hash;\n }\n for (let i = 0; i < str.length; i++) {\n const chr = str.charCodeAt(i);\n // eslint-disable-next-line no-bitwise\n hash = ((hash << 5) - hash) + chr;\n // eslint-disable-next-line no-bitwise\n hash |= 0; // Convert to 32bit integer\n }\n return hash;\n }\n\n /**\n * Takes an array of strings and returns a hash of the items\n */\n private _generateHash(items: string[]): string {\n // We sort the items before joining them to ensure correct hash generation\n // every time\n const files = items.sort().join('|');\n const hash = \"\" + this._hashCode(files);\n return hash;\n }\n\n /**\n * Update the revision of a key in it's parent folder data\n */\n private _updateParentFolderItemRev(key: string, rev): void {\n if (key !== '/') {\n const parentFolder = this._getParentFolder(key);\n if (!this._itemsRev[parentFolder]) {\n this._itemsRev[parentFolder] = {};\n }\n const parentFolderItemsRev = this._itemsRev[parentFolder];\n if (!rev) {\n delete parentFolderItemsRev[key];\n } else {\n parentFolderItemsRev[key] = rev;\n }\n //reset revision until root\n this._updateParentFolderItemRev(parentFolder, this.defaultValue);\n }\n }\n\n private _getParentFolder(key: string): string {\n return key.substr(0, key.lastIndexOf('/', key.length - 2) + 1);\n }\n\n /**\n * Propagate the changes to the parent folders and generate new revision ids\n * for them\n */\n private _propagate(key: string): void {\n if (key !== '/') {\n const parentFolder = this._getParentFolder(key);\n const parentFolderItemsRev = this._itemsRev[parentFolder];\n const hashItems = [];\n for (const path in parentFolderItemsRev) {\n hashItems.push(parentFolderItemsRev[path]);\n }\n const newRev = this._generateHash(hashItems);\n this.set(parentFolder, newRev);\n }\n }\n\n /**\n * Generate revision id for a folder and it's subfolders, by hashing it's\n * listing\n */\n private _generateFolderRev(folder: string): string {\n const itemsRev = this._itemsRev[folder];\n let hash = this.defaultValue;\n if (itemsRev) {\n const hashItems = [];\n for (const path in itemsRev) {\n const isDir: boolean = (path.substr(-1) === '/');\n let hashItem;\n if (isDir) {\n hashItem = this._generateFolderRev(path);\n } else {\n hashItem = itemsRev[path];\n }\n hashItems.push(hashItem);\n }\n if (hashItems.length > 0) {\n hash = this._generateHash(hashItems);\n }\n }\n this.set(folder, hash);\n return hash;\n }\n}\n\nexport = RevisionCache;\n","/* global define */\n/*!\n * webfinger.js\n * http://github.com/silverbucket/webfinger.js\n *\n * Developed and Maintained by:\n * Nick Jennings \n *\n * webfinger.js is released under the AGPL (see LICENSE).\n *\n * You don't have to do anything special to choose one license or the other and you don't\n * have to notify anyone which license you are using.\n * Please see the corresponding license file for details of these licenses.\n * You are free to use, modify and distribute this software, but all copyright\n * information must remain.\n *\n */\n\nif (typeof fetch !== 'function' && typeof XMLHttpRequest !== 'function') {\n // XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;\n XMLHttpRequest = require('xhr2');\n}\n\n(function (global) {\n\n // URI to property name map\n var LINK_URI_MAPS = {\n 'http://webfist.org/spec/rel': 'webfist',\n 'http://webfinger.net/rel/avatar': 'avatar',\n 'remotestorage': 'remotestorage',\n 'http://tools.ietf.org/id/draft-dejong-remotestorage': 'remotestorage',\n 'remoteStorage': 'remotestorage',\n 'http://www.packetizer.com/rel/share': 'share',\n 'http://webfinger.net/rel/profile-page': 'profile',\n 'me': 'profile',\n 'vcard': 'vcard',\n 'blog': 'blog',\n 'http://packetizer.com/rel/blog': 'blog',\n 'http://schemas.google.com/g/2010#updates-from': 'updates',\n 'https://camlistore.org/rel/server': 'camilstore'\n };\n\n var LINK_PROPERTIES = {\n 'avatar': [],\n 'remotestorage': [],\n 'blog': [],\n 'vcard': [],\n 'updates': [],\n 'share': [],\n 'profile': [],\n 'webfist': [],\n 'camlistore': []\n };\n\n // list of endpoints to try, fallback from beginning to end.\n var URIS = ['webfinger', 'host-meta', 'host-meta.json'];\n\n function generateErrorObject(obj) {\n obj.toString = function () {\n return this.message;\n };\n return obj;\n }\n\n // given a URL ensures it's HTTPS.\n // returns false for null string or non-HTTPS URL.\n function isSecure(url) {\n if (typeof url !== 'string') {\n return false;\n }\n var parts = url.split('://');\n if (parts[0] === 'https') {\n return true;\n }\n return false;\n }\n\n /**\n * Function: WebFinger\n *\n * WebFinger constructor\n *\n * Returns:\n *\n * return WebFinger object\n */\n function WebFinger(config) {\n if (typeof config !== 'object') {\n config = {};\n }\n\n this.config = {\n tls_only: (typeof config.tls_only !== 'undefined') ? config.tls_only : true,\n webfist_fallback: (typeof config.webfist_fallback !== 'undefined') ? config.webfist_fallback : false,\n uri_fallback: (typeof config.uri_fallback !== 'undefined') ? config.uri_fallback : false,\n request_timeout: (typeof config.request_timeout !== 'undefined') ? config.request_timeout : 10000\n };\n }\n\n // make an http request and look for JRD response, fails if request fails\n // or response not json.\n WebFinger.prototype.__fetchJRD = function (url, errorHandler, successHandler) {\n if (typeof fetch === 'function') {\n return this.__fetchJRD_fetch(url, errorHandler, successHandler);\n } else if (typeof XMLHttpRequest === 'function') {\n return this.__fetchJRD_XHR(url, errorHandler, successHandler);\n } else {\n throw new Error(\"add a polyfill for fetch or XMLHttpRequest\");\n }\n };\n WebFinger.prototype.__fetchJRD_fetch = function (url, errorHandler, successHandler) {\n var webfinger = this;\n var abortController;\n if (typeof AbortController === 'function') {\n abortController = new AbortController();\n }\n var networkPromise = fetch(url, {\n headers: {'Accept': 'application/jrd+json, application/json'},\n signal: abortController ? abortController.signal : undefined\n }).\n then(function (response) {\n if (response.ok) {\n return response.text();\n } else if (response.status === 404) {\n throw generateErrorObject({\n message: 'resource not found',\n url: url,\n status: response.status\n });\n } else { // other HTTP status (redirects are handled transparently)\n throw generateErrorObject({\n message: 'error during request',\n url: url,\n status: response.status\n });\n }\n },\n function (err) { // connection refused, etc.\n throw generateErrorObject({\n message: 'error during request',\n url: url,\n status: undefined,\n err: err\n })\n }).\n then(function (responseText) {\n if (webfinger.__isValidJSON(responseText)) {\n return responseText;\n } else {\n throw generateErrorObject({\n message: 'invalid json',\n url: url,\n status: undefined\n });\n }\n });\n\n var timeoutPromise = new Promise(function (resolve, reject) {\n setTimeout(function () {\n reject(generateErrorObject({\n message: 'request timed out',\n url: url,\n status: undefined\n }));\n if (abortController) {\n abortController.abort();\n }\n }, webfinger.config.request_timeout);\n });\n\n Promise.race([networkPromise, timeoutPromise]).\n then(function (responseText) {\n successHandler(responseText);\n }).catch(function (err) {\n errorHandler(err);\n });\n };\n WebFinger.prototype.__fetchJRD_XHR = function (url, errorHandler, successHandler) {\n var self = this;\n var handlerSpent = false;\n var xhr = new XMLHttpRequest();\n\n function __processState() {\n if (handlerSpent){\n return;\n }else{\n handlerSpent = true;\n }\n\n if (xhr.status === 200) {\n if (self.__isValidJSON(xhr.responseText)) {\n return successHandler(xhr.responseText);\n } else {\n return errorHandler(generateErrorObject({\n message: 'invalid json',\n url: url,\n status: xhr.status\n }));\n }\n } else if (xhr.status === 404) {\n return errorHandler(generateErrorObject({\n message: 'resource not found',\n url: url,\n status: xhr.status\n }));\n } else if ((xhr.status >= 301) && (xhr.status <= 302)) {\n var location = xhr.getResponseHeader('Location');\n if (isSecure(location)) {\n return __makeRequest(location); // follow redirect\n } else {\n return errorHandler(generateErrorObject({\n message: 'no redirect URL found',\n url: url,\n status: xhr.status\n }));\n }\n } else {\n return errorHandler(generateErrorObject({\n message: 'error during request',\n url: url,\n status: xhr.status\n }));\n }\n }\n\n function __makeRequest() {\n xhr.onreadystatechange = function () {\n if (xhr.readyState === 4) {\n __processState();\n }\n };\n\n xhr.onload = function () {\n __processState();\n };\n\n xhr.ontimeout = function () {\n return errorHandler(generateErrorObject({\n message: 'request timed out',\n url: url,\n status: xhr.status\n }));\n };\n\n xhr.open('GET', url, true);\n xhr.timeout = self.config.request_timeout;\n xhr.setRequestHeader('Accept', 'application/jrd+json, application/json');\n xhr.send();\n }\n\n return __makeRequest();\n };\n\n WebFinger.prototype.__isValidJSON = function (str) {\n try {\n JSON.parse(str);\n } catch (e) {\n return false;\n }\n return true;\n };\n\n WebFinger.prototype.__isLocalhost = function (host) {\n var local = /^localhost(\\.localdomain)?(\\:[0-9]+)?$/;\n return local.test(host);\n };\n\n // processes JRD object as if it's a webfinger response object\n // looks for known properties and adds them to profile datat struct.\n WebFinger.prototype.__processJRD = function (URL, JRD, errorHandler, successHandler) {\n var parsedJRD = JSON.parse(JRD);\n if ((typeof parsedJRD !== 'object') ||\n (typeof parsedJRD.links !== 'object')) {\n if (typeof parsedJRD.error !== 'undefined') {\n return errorHandler(generateErrorObject({ message: parsedJRD.error, request: URL }));\n } else {\n return errorHandler(generateErrorObject({ message: 'unknown response from server', request: URL }));\n }\n }\n\n var links = parsedJRD.links;\n if (!Array.isArray(links)) {\n links = [];\n }\n var result = { // webfinger JRD - object, json, and our own indexing\n object: parsedJRD,\n json: JRD,\n idx: {}\n };\n\n result.idx.properties = {\n 'name': undefined\n };\n result.idx.links = JSON.parse(JSON.stringify(LINK_PROPERTIES));\n\n // process links\n links.map(function (link, i) {\n if (LINK_URI_MAPS.hasOwnProperty(link.rel)) {\n if (result.idx.links[LINK_URI_MAPS[link.rel]]) {\n var entry = {};\n Object.keys(link).map(function (item, n) {\n entry[item] = link[item];\n });\n result.idx.links[LINK_URI_MAPS[link.rel]].push(entry);\n }\n }\n });\n\n // process properties\n var props = JSON.parse(JRD).properties;\n for (var key in props) {\n if (props.hasOwnProperty(key)) {\n if (key === 'http://packetizer.com/ns/name') {\n result.idx.properties.name = props[key];\n }\n }\n }\n return successHandler(result);\n };\n\n WebFinger.prototype.lookup = function (address, cb) {\n if (typeof address !== 'string') {\n throw new Error('first parameter must be a user address');\n } else if (typeof cb !== 'function') {\n throw new Error('second parameter must be a callback');\n }\n\n var self = this;\n var host = '';\n if (address.indexOf('://') > -1) {\n // other uri format\n host = address.replace(/ /g,'').split('/')[2];\n } else {\n // useraddress\n host = address.replace(/ /g,'').split('@')[1];\n }\n var uri_index = 0; // track which URIS we've tried already\n var protocol = 'https'; // we use https by default\n\n if (self.__isLocalhost(host)) {\n protocol = 'http';\n }\n\n function __buildURL() {\n var uri = '';\n if (! address.split('://')[1]) {\n // the URI has not been defined, default to acct\n uri = 'acct:';\n }\n return protocol + '://' + host + '/.well-known/' +\n URIS[uri_index] + '?resource=' + uri + address;\n }\n\n // control flow for failures, what to do in various cases, etc.\n function __fallbackChecks(err) {\n if ((self.config.uri_fallback) && (host !== 'webfist.org') && (uri_index !== URIS.length - 1)) { // we have uris left to try\n uri_index = uri_index + 1;\n return __call();\n } else if ((!self.config.tls_only) && (protocol === 'https')) { // try normal http\n uri_index = 0;\n protocol = 'http';\n return __call();\n } else if ((self.config.webfist_fallback) && (host !== 'webfist.org')) { // webfist attempt\n uri_index = 0;\n protocol = 'http';\n host = 'webfist.org';\n // webfist will\n // 1. make a query to the webfist server for the users account\n // 2. from the response, get a link to the actual webfinger json data\n // (stored somewhere in control of the user)\n // 3. make a request to that url and get the json\n // 4. process it like a normal webfinger response\n var URL = __buildURL();\n self.__fetchJRD(URL, cb, function (data) { // get link to users JRD\n self.__processJRD(URL, data, cb, function (result) {\n if ((typeof result.idx.links.webfist === 'object') &&\n (typeof result.idx.links.webfist[0].href === 'string')) {\n self.__fetchJRD(result.idx.links.webfist[0].href, cb, function (JRD) {\n self.__processJRD(URL, JRD, cb, function (result) {\n return cb(null, cb);\n });\n });\n }\n });\n });\n } else {\n return cb(err);\n }\n }\n\n function __call() {\n // make request\n var URL = __buildURL();\n self.__fetchJRD(URL, __fallbackChecks, function (JRD) {\n self.__processJRD(URL, JRD, cb, function (result) { cb(null, result); });\n });\n }\n\n return setTimeout(__call, 0);\n };\n\n WebFinger.prototype.lookupLink = function (address, rel, cb) {\n if (LINK_PROPERTIES.hasOwnProperty(rel)) {\n this.lookup(address, function (err, p) {\n var links = p.idx.links[rel];\n if (err) {\n return cb(err);\n } else if (links.length === 0) {\n return cb('no links found with rel=\"' + rel + '\"');\n } else {\n return cb(null, links[0]);\n }\n });\n } else {\n return cb('unsupported rel ' + rel);\n }\n };\n\n\n\n // AMD support\n if (typeof define === 'function' && define.amd) {\n define([], function () { return WebFinger; });\n // CommonJS and Node.js module support.\n } else if (typeof exports !== 'undefined') {\n // Support Node.js specific `module.exports` (which can be a function)\n if (typeof module !== 'undefined' && module.exports) {\n exports = module.exports = WebFinger;\n }\n // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function)\n exports.WebFinger = WebFinger;\n } else {\n // browser