--- a/services/common/kinto-http-client.js
+++ b/services/common/kinto-http-client.js
@@ -18,20 +18,20 @@
* This file is generated from kinto-http.js - do not modify directly.
*/
const global = this;
this.EXPORTED_SYMBOLS = ["KintoHttpClient"];
/*
- * Version 4.3.4 - 1294207
+ * Version 4.5.3 - 5179c56
*/
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.KintoHttpClient = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.KintoHttpClient = f()}})(function(){var define,module,exports;return (function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){
/*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@@ -44,149 +44,161 @@ this.EXPORTED_SYMBOLS = ["KintoHttpClien
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = undefined;
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
var _base = require("../src/base");
var _base2 = _interopRequireDefault(_base);
+var _errors = require("../src/errors");
+
+var errors = _interopRequireWildcard(_errors);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
ChromeUtils.import("resource://gre/modules/Timer.jsm");
-Cu.importGlobalProperties(['fetch']);
+Cu.importGlobalProperties(["fetch"]);
const { EventEmitter } = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm", {});
let KintoHttpClient = class KintoHttpClient extends _base2.default {
constructor(remote, options = {}) {
const events = {};
EventEmitter.decorate(events);
- super(remote, _extends({ events }, options));
+ super(remote, { events, ...options });
}
};
+exports.default = KintoHttpClient;
+
+
+KintoHttpClient.errors = errors;
// This fixes compatibility with CommonJS required by browserify.
// See http://stackoverflow.com/questions/33505992/babel-6-changes-how-it-exports-default/33683495#33683495
-
-exports.default = KintoHttpClient;
if (typeof module === "object") {
module.exports = KintoHttpClient;
}
-},{"../src/base":7}],2:[function(require,module,exports){
+},{"../src/base":7,"../src/errors":12}],2:[function(require,module,exports){
var v1 = require('./v1');
var v4 = require('./v4');
var uuid = v4;
uuid.v1 = v1;
uuid.v4 = v4;
module.exports = uuid;
},{"./v1":5,"./v4":6}],3:[function(require,module,exports){
/**
* Convert array of 16 byte values to UUID string format of the form:
- * XXXXXXXX-XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+ * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
*/
var byteToHex = [];
for (var i = 0; i < 256; ++i) {
byteToHex[i] = (i + 0x100).toString(16).substr(1);
}
function bytesToUuid(buf, offset) {
var i = offset || 0;
var bth = byteToHex;
- return bth[buf[i++]] + bth[buf[i++]] +
+ return bth[buf[i++]] + bth[buf[i++]] +
bth[buf[i++]] + bth[buf[i++]] + '-' +
bth[buf[i++]] + bth[buf[i++]] + '-' +
bth[buf[i++]] + bth[buf[i++]] + '-' +
bth[buf[i++]] + bth[buf[i++]] + '-' +
bth[buf[i++]] + bth[buf[i++]] +
bth[buf[i++]] + bth[buf[i++]] +
bth[buf[i++]] + bth[buf[i++]];
}
module.exports = bytesToUuid;
},{}],4:[function(require,module,exports){
// Unique ID creation requires a high quality random # generator. In the
// browser this is a little complicated due to unknown quality of Math.random()
// and inconsistent support for the `crypto` API. We do the best we can via
// feature-detection
-var rng;
-var crypto = global.crypto || global.msCrypto; // for IE 11
-if (crypto && crypto.getRandomValues) {
+// getRandomValues needs to be invoked in a context where "this" is a Crypto implementation.
+var getRandomValues = (typeof(crypto) != 'undefined' && crypto.getRandomValues.bind(crypto)) ||
+ (typeof(msCrypto) != 'undefined' && msCrypto.getRandomValues.bind(msCrypto));
+if (getRandomValues) {
// WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
- var rnds8 = new Uint8Array(16);
- rng = function whatwgRNG() {
- crypto.getRandomValues(rnds8);
+ var rnds8 = new Uint8Array(16); // eslint-disable-line no-undef
+
+ module.exports = function whatwgRNG() {
+ getRandomValues(rnds8);
return rnds8;
};
-}
-
-if (!rng) {
+} else {
// Math.random()-based (RNG)
//
// If all else fails, use Math.random(). It's fast, but is of unspecified
// quality.
- var rnds = new Array(16);
- rng = function() {
+ var rnds = new Array(16);
+
+ module.exports = function mathRNG() {
for (var i = 0, r; i < 16; i++) {
if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
}
return rnds;
};
}
-module.exports = rng;
-
},{}],5:[function(require,module,exports){
-// Unique ID creation requires a high quality random # generator. We feature
-// detect to determine the best RNG source, normalizing to a function that
-// returns 128-bits of randomness, since that's what's usually required
var rng = require('./lib/rng');
var bytesToUuid = require('./lib/bytesToUuid');
// **`v1()` - Generate time-based UUID**
//
// Inspired by https://github.com/LiosK/UUID.js
// and http://docs.python.org/library/uuid.html
-// random #'s we need to init node and clockseq
-var _seedBytes = rng();
-
-// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
-var _nodeId = [
- _seedBytes[0] | 0x01,
- _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
-];
-
-// Per 4.2.2, randomize (14 bit) clockseq
-var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
+var _nodeId;
+var _clockseq;
// Previous uuid creation time
-var _lastMSecs = 0, _lastNSecs = 0;
+var _lastMSecs = 0;
+var _lastNSecs = 0;
// See https://github.com/broofa/node-uuid for API details
function v1(options, buf, offset) {
var i = buf && offset || 0;
var b = buf || [];
options = options || {};
+ var node = options.node || _nodeId;
+ var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
- var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
+ // node and clockseq need to be initialized to random values if they're not
+ // specified. We do this lazily to minimize issues related to insufficient
+ // system entropy. See #189
+ if (node == null || clockseq == null) {
+ var seedBytes = rng();
+ if (node == null) {
+ // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
+ node = _nodeId = [
+ seedBytes[0] | 0x01,
+ seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]
+ ];
+ }
+ if (clockseq == null) {
+ // Per 4.2.2, randomize (14 bit) clockseq
+ clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff;
+ }
+ }
// UUID timestamps are 100 nano-second units since the Gregorian epoch,
// (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
// time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
// (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime();
// Per 4.2.1.2, use count of uuid's generated during the current clock
@@ -237,17 +249,16 @@ function v1(options, buf, offset) {
// `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
b[i++] = clockseq >>> 8 | 0x80;
// `clock_seq_low`
b[i++] = clockseq & 0xff;
// `node`
- var node = options.node || _nodeId;
for (var n = 0; n < 6; ++n) {
b[i + n] = node[n];
}
return buf ? buf : bytesToUuid(b);
}
module.exports = v1;
@@ -255,17 +266,17 @@ module.exports = v1;
},{"./lib/bytesToUuid":3,"./lib/rng":4}],6:[function(require,module,exports){
var rng = require('./lib/rng');
var bytesToUuid = require('./lib/bytesToUuid');
function v4(options, buf, offset) {
var i = buf && offset || 0;
if (typeof(options) == 'string') {
- buf = options == 'binary' ? new Array(16) : null;
+ buf = options === 'binary' ? new Array(16) : null;
options = null;
}
options = options || {};
var rnds = options.random || (options.rng || rng)();
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
rnds[6] = (rnds[6] & 0x0f) | 0x40;
@@ -286,18 +297,16 @@ module.exports = v4;
},{"./lib/bytesToUuid":3,"./lib/rng":4}],7:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.SUPPORTED_PROTOCOL_VERSION = undefined;
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _desc, _value, _class;
var _utils = require("./utils");
var _http = require("./http");
var _http2 = _interopRequireDefault(_http);
@@ -355,18 +364,18 @@ function _applyDecoratedDescriptor(targe
const SUPPORTED_PROTOCOL_VERSION = exports.SUPPORTED_PROTOCOL_VERSION = "v1";
/**
* High level HTTP client for the Kinto API.
*
* @example
* const client = new KintoClient("https://kinto.dev.mozaws.net/v1");
* client.bucket("default")
-* .collection("my-blog")
-* .createRecord({title: "First article"})
+ * .collection("my-blog")
+ * .createRecord({title: "First article"})
* .then(console.log.bind(console))
* .catch(console.error.bind(console));
*/
let KintoClientBase = (_dec = (0, _utils.nobatch)("This operation is not supported within a batch operation."), _dec2 = (0, _utils.nobatch)("This operation is not supported within a batch operation."), _dec3 = (0, _utils.nobatch)("This operation is not supported within a batch operation."), _dec4 = (0, _utils.nobatch)("This operation is not supported within a batch operation."), _dec5 = (0, _utils.nobatch)("Can't use batch within a batch!"), _dec6 = (0, _utils.capable)(["permissions_endpoint"]), _dec7 = (0, _utils.support)("1.4", "2.0"), (_class = class KintoClientBase {
/**
* Constructor.
*
* @param {String} remote The remote URL.
@@ -500,50 +509,66 @@ let KintoClientBase = (_dec = (0, _utils
batch: this._isBatch,
headers: this._getHeaders(options),
safe: this._getSafe(options),
retry: this._getRetry(options)
});
}
/**
+ * Set client "headers" for every request, updating previous headers (if any).
+ *
+ * @param {Object} headers The headers to merge with existing ones.
+ */
+ setHeaders(headers) {
+ this._headers = {
+ ...this._headers,
+ ...headers
+ };
+ this.serverInfo = null;
+ }
+
+ /**
* Get the value of "headers" for a given request, merging the
* per-request headers with our own "default" headers.
*
* Note that unlike other options, headers aren't overridden, but
* merged instead.
*
* @private
* @param {Object} options The options for a request.
* @returns {Object}
*/
_getHeaders(options) {
- return _extends({}, this._headers, options.headers);
+ return {
+ ...this._headers,
+ ...options.headers
+ };
}
/**
* Get the value of "safe" for a given request, using the
* per-request option if present or falling back to our default
* otherwise.
*
* @private
* @param {Object} options The options for a request.
* @returns {Boolean}
*/
_getSafe(options) {
- return _extends({ safe: this._safe }, options).safe;
+ return { safe: this._safe, ...options }.safe;
}
/**
* As _getSafe, but for "retry".
*
* @private
*/
_getRetry(options) {
- return _extends({ retry: this._retry }, options).retry;
+ return { retry: this._retry, ...options }.retry;
}
/**
* Retrieves the server's "hello" endpoint. This endpoint reveals
* server capabilities and settings as well as telling the client
* "who they are" according to their given authorization headers.
*
* @private
@@ -782,29 +807,31 @@ let KintoClientBase = (_dec = (0, _utils
* @param {Number} [options.retry=0]
* Number of times to retry each request if the server responds
* with Retry-After.
*/
async paginatedList(path, params, options = {}) {
// FIXME: this is called even in batch requests, which doesn't
// make any sense (since all batch requests get a "dummy"
// response; see execute() above).
- const { sort, filters, limit, pages, since } = _extends({
- sort: "-last_modified"
- }, params);
+ const { sort, filters, limit, pages, since } = {
+ sort: "-last_modified",
+ ...params
+ };
// Safety/Consistency check on ETag value.
if (since && typeof since !== "string") {
throw new Error(`Invalid value for since (${since}), should be ETag value.`);
}
- const querystring = (0, _utils.qsify)(_extends({}, filters, {
+ const querystring = (0, _utils.qsify)({
+ ...filters,
_sort: sort,
_limit: limit,
_since: since
- }));
+ });
let results = [],
current = 0;
const next = async function (nextPage) {
if (!nextPage) {
throw new Error("Pagination exhausted.");
}
return processNextPage(nextPage);
@@ -867,17 +894,17 @@ let KintoClientBase = (_dec = (0, _utils
* when faced with transient errors.
* @return {Promise<Object[], Error>}
*/
async listPermissions(options = {}) {
const path = (0, _endpoint2.default)("permissions");
// Ensure the default sort parameter is something that exists in permissions
// entries, as `last_modified` doesn't; here, we pick "id".
- const paginationOptions = _extends({ sort: "id" }, options);
+ const paginationOptions = { sort: "id", ...options };
return this.paginatedList(path, paginationOptions, {
headers: this._getHeaders(options),
retry: this._getRetry(options)
});
}
/**
* Retrieves the list of buckets.
@@ -935,17 +962,17 @@ let KintoClientBase = (_dec = (0, _utils
* @return {Promise<Object, Error>}
*/
async deleteBucket(bucket, options = {}) {
const bucketObj = (0, _utils.toDataBody)(bucket);
if (!bucketObj.id) {
throw new Error("A bucket id is required.");
}
const path = (0, _endpoint2.default)("bucket", bucketObj.id);
- const { last_modified } = _extends({}, bucketObj, options);
+ const { last_modified } = { ...bucketObj, ...options };
return this.execute(requests.deleteRequest(path, {
last_modified,
headers: this._getHeaders(options),
safe: this._getSafe(options)
}), { retry: this._getRetry(options) });
}
/**
@@ -997,17 +1024,17 @@ function aggregate(responses = [], reque
};
return responses.reduce((acc, response, index) => {
const { status } = response;
const request = requests[index];
if (status >= 200 && status < 400) {
acc.published.push(response.body);
} else if (status === 404) {
// Extract the id manually from request path while waiting for Kinto/kinto#818
- const regex = /(buckets|groups|collections|records)\/([^\/]+)$/;
+ const regex = /(buckets|groups|collections|records)\/([^/]+)$/;
const extracts = request.path.match(regex);
const id = extracts.length === 3 ? extracts[2] : undefined;
acc.skipped.push({
id,
path: request.path,
error: response.body
});
} else if (status === 412) {
@@ -1031,18 +1058,16 @@ function aggregate(responses = [], reque
},{}],9:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = undefined;
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
var _dec, _desc, _value, _class;
var _utils = require("./utils");
var _collection = require("./collection");
var _collection2 = _interopRequireDefault(_collection);
@@ -1126,39 +1151,42 @@ let Bucket = (_dec = (0, _utils.capable)
/**
* Get the value of "headers" for a given request, merging the
* per-request headers with our own "default" headers.
*
* @private
*/
_getHeaders(options) {
- return _extends({}, this._headers, options.headers);
+ return {
+ ...this._headers,
+ ...options.headers
+ };
}
/**
* Get the value of "safe" for a given request, using the
* per-request option if present or falling back to our default
* otherwise.
*
* @private
* @param {Object} options The options for a request.
* @returns {Boolean}
*/
_getSafe(options) {
- return _extends({ safe: this._safe }, options).safe;
+ return { safe: this._safe, ...options }.safe;
}
/**
* As _getSafe, but for "retry".
*
* @private
*/
_getRetry(options) {
- return _extends({ retry: this._retry }, options).retry;
+ return { retry: this._retry, ...options }.retry;
}
/**
* Selects a collection.
*
* @param {String} name The collection name.
* @param {Object} [options={}] The options object.
* @param {Object} [options.headers] The headers object option.
@@ -1206,28 +1234,28 @@ let Bucket = (_dec = (0, _utils.capable)
* @param {Number} [options.last_modified] The last_modified option.
* @return {Promise<Object, Error>}
*/
async setData(data, options = {}) {
if (!(0, _utils.isObject)(data)) {
throw new Error("A bucket object is required.");
}
- const bucket = _extends({}, data, { id: this.name });
+ const bucket = { ...data, id: this.name };
// For default bucket, we need to drop the id from the data object.
// Bug in Kinto < 3.1.1
const bucketId = bucket.id;
if (bucket.id === "default") {
delete bucket.id;
}
const path = (0, _endpoint2.default)("bucket", bucketId);
const { patch, permissions } = options;
- const { last_modified } = _extends({}, data, options);
+ const { last_modified } = { ...data, ...options };
const request = requests.updateRequest(path, { data: bucket, permissions }, {
last_modified,
patch,
headers: this._getHeaders(options),
safe: this._getSafe(options)
});
return this.client.execute(request, { retry: this._getRetry(options) });
}
@@ -1304,17 +1332,17 @@ let Bucket = (_dec = (0, _utils.capable)
* @return {Promise<Object, Error>}
*/
async deleteCollection(collection, options = {}) {
const collectionObj = (0, _utils.toDataBody)(collection);
if (!collectionObj.id) {
throw new Error("A collection id is required.");
}
const { id } = collectionObj;
- const { last_modified } = _extends({}, collectionObj, options);
+ const { last_modified } = { ...collectionObj, ...options };
const path = (0, _endpoint2.default)("collection", this.name, id);
const request = requests.deleteRequest(path, {
last_modified,
headers: this._getHeaders(options),
safe: this._getSafe(options)
});
return this.client.execute(request, { retry: this._getRetry(options) });
}
@@ -1364,20 +1392,21 @@ let Bucket = (_dec = (0, _utils.capable)
* @param {Object} [options.permissions] The permissions object.
* @param {Boolean} [options.safe] The safe option.
* @param {Object} [options.headers] The headers object option.
* @param {Number} [options.retry=0] Number of retries to make
* when faced with transient errors.
* @return {Promise<Object, Error>}
*/
async createGroup(id, members = [], options = {}) {
- const data = _extends({}, options.data, {
+ const data = {
+ ...options.data,
id,
members
- });
+ };
const path = (0, _endpoint2.default)("group", this.name, id);
const { permissions } = options;
const request = requests.createRequest(path, { data, permissions }, {
headers: this._getHeaders(options),
safe: this._getSafe(options)
});
return this.client.execute(request, { retry: this._getRetry(options) });
}
@@ -1398,20 +1427,23 @@ let Bucket = (_dec = (0, _utils.capable)
*/
async updateGroup(group, options = {}) {
if (!(0, _utils.isObject)(group)) {
throw new Error("A group object is required.");
}
if (!group.id) {
throw new Error("A group id is required.");
}
- const data = _extends({}, options.data, group);
+ const data = {
+ ...options.data,
+ ...group
+ };
const path = (0, _endpoint2.default)("group", this.name, group.id);
const { patch, permissions } = options;
- const { last_modified } = _extends({}, data, options);
+ const { last_modified } = { ...data, ...options };
const request = requests.updateRequest(path, { data, permissions }, {
last_modified,
patch,
headers: this._getHeaders(options),
safe: this._getSafe(options)
});
return this.client.execute(request, { retry: this._getRetry(options) });
}
@@ -1426,17 +1458,17 @@ let Bucket = (_dec = (0, _utils.capable)
* when faced with transient errors.
* @param {Boolean} [options.safe] The safe option.
* @param {Number} [options.last_modified] The last_modified option.
* @return {Promise<Object, Error>}
*/
async deleteGroup(group, options = {}) {
const groupObj = (0, _utils.toDataBody)(group);
const { id } = groupObj;
- const { last_modified } = _extends({}, groupObj, options);
+ const { last_modified } = { ...groupObj, ...options };
const path = (0, _endpoint2.default)("group", this.name, id);
const request = requests.deleteRequest(path, {
last_modified,
headers: this._getHeaders(options),
safe: this._getSafe(options)
});
return this.client.execute(request, { retry: this._getRetry(options) });
}
@@ -1565,18 +1597,16 @@ exports.default = Bucket;
},{"./collection":10,"./endpoint":11,"./requests":14,"./utils":15}],10:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = undefined;
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
var _dec, _dec2, _dec3, _desc, _value, _class;
var _uuid = require("uuid");
var _utils = require("./utils");
var _requests = require("./requests");
@@ -1659,49 +1689,55 @@ let Collection = (_dec = (0, _utils.capa
/**
* @ignore
*/
this._retry = options.retry || 0;
this._safe = !!options.safe;
// FIXME: This is kind of ugly; shouldn't the bucket be responsible
// for doing the merge?
- this._headers = _extends({}, this.bucket._headers, options.headers);
+ this._headers = {
+ ...this.bucket._headers,
+ ...options.headers
+ };
}
/**
* Get the value of "headers" for a given request, merging the
* per-request headers with our own "default" headers.
*
* @private
*/
_getHeaders(options) {
- return _extends({}, this._headers, options.headers);
+ return {
+ ...this._headers,
+ ...options.headers
+ };
}
/**
* Get the value of "safe" for a given request, using the
* per-request option if present or falling back to our default
* otherwise.
*
* @private
* @param {Object} options The options for a request.
* @returns {Boolean}
*/
_getSafe(options) {
- return _extends({ safe: this._safe }, options).safe;
+ return { safe: this._safe, ...options }.safe;
}
/**
* As _getSafe, but for "retry".
*
* @private
*/
_getRetry(options) {
- return _extends({ retry: this._retry }, options).retry;
+ return { retry: this._retry, ...options }.retry;
}
/**
* Retrieves the total number of records in this collection.
*
* @param {Object} [options={}] The options object.
* @param {Object} [options.headers] The headers object option.
* @param {Number} [options.retry=0] Number of retries to make
@@ -1752,17 +1788,17 @@ let Collection = (_dec = (0, _utils.capa
* @param {Number} [options.last_modified] The last_modified option.
* @return {Promise<Object, Error>}
*/
async setData(data, options = {}) {
if (!(0, _utils.isObject)(data)) {
throw new Error("A collection object is required.");
}
const { patch, permissions } = options;
- const { last_modified } = _extends({}, data, options);
+ const { last_modified } = { ...data, ...options };
const path = (0, _endpoint2.default)("collection", this.bucket.name, this.name);
const request = requests.updateRequest(path, { data, permissions }, {
last_modified,
patch,
headers: this._getHeaders(options),
safe: this._getSafe(options)
});
@@ -1902,17 +1938,17 @@ let Collection = (_dec = (0, _utils.capa
* @param {String} [options.gzipped] Force the attachment to be gzipped or not.
* @return {Promise<Object, Error>}
*/
async addAttachment(dataURI, record = {}, options = {}) {
const { permissions } = options;
const id = record.id || _uuid.v4.v4();
const path = (0, _endpoint2.default)("attachment", this.bucket.name, this.name, id);
- const { last_modified } = _extends({}, record, options);
+ const { last_modified } = { ...record, ...options };
const addAttachmentRequest = requests.addAttachmentRequest(path, dataURI, { data: record, permissions }, {
last_modified,
filename: options.filename,
gzipped: options.gzipped,
headers: this._getHeaders(options),
safe: this._getSafe(options)
});
await this.client.execute(addAttachmentRequest, {
@@ -1961,17 +1997,17 @@ let Collection = (_dec = (0, _utils.capa
async updateRecord(record, options = {}) {
if (!(0, _utils.isObject)(record)) {
throw new Error("A record object is required.");
}
if (!record.id) {
throw new Error("A record id is required.");
}
const { permissions } = options;
- const { last_modified } = _extends({}, record, options);
+ const { last_modified } = { ...record, ...options };
const path = (0, _endpoint2.default)("record", this.bucket.name, this.name, record.id);
const request = requests.updateRequest(path, { data: record, permissions }, {
headers: this._getHeaders(options),
safe: this._getSafe(options),
last_modified,
patch: !!options.patch
});
return this.client.execute(request, { retry: this._getRetry(options) });
@@ -1990,17 +2026,17 @@ let Collection = (_dec = (0, _utils.capa
* @return {Promise<Object, Error>}
*/
async deleteRecord(record, options = {}) {
const recordObj = (0, _utils.toDataBody)(record);
if (!recordObj.id) {
throw new Error("A record id is required.");
}
const { id } = recordObj;
- const { last_modified } = _extends({}, recordObj, options);
+ const { last_modified } = { ...recordObj, ...options };
const path = (0, _endpoint2.default)("record", this.bucket.name, this.name, id);
const request = requests.deleteRequest(path, {
last_modified,
headers: this._getHeaders(options),
safe: this._getSafe(options)
});
return this.client.execute(request, { retry: this._getRetry(options) });
}
@@ -2095,17 +2131,18 @@ let Collection = (_dec = (0, _utils.capa
throw new Error("Computing a snapshot is only possible when the full history for a " + "collection is available. Here, the history plugin seems to have " + "been enabled after the creation of the collection.");
}
const { data: changes } = await this.bucket.listHistory({
pages: Infinity, // all pages up to target timestamp are required
sort: "-target.data.last_modified",
filters: {
resource_name: "record",
collection_id: this.name,
- "max_target.data.last_modified": String(at) }
+ "max_target.data.last_modified": String(at) // eq. to <=
+ }
});
return changes;
}
/**
* @private
*/
@@ -2113,19 +2150,17 @@ let Collection = (_dec = (0, _utils.capa
if (!Number.isInteger(at) || at <= 0) {
throw new Error("Invalid argument, expected a positive integer.");
}
// Retrieve history and check it covers the required time range.
const changes = await this.listChangesBackTo(at);
// Replay changes to compute the requested snapshot.
const seenIds = new Set();
let snapshot = [];
- for (const _ref of changes) {
- const { action, target: { data: record } } = _ref;
-
+ for (const { action, target: { data: record } } of changes) {
if (action == "delete") {
seenIds.add(record.id); // ensure not reprocessing deleted entries
snapshot = snapshot.filter(r => r.id !== record.id);
} else if (!seenIds.has(record.id)) {
seenIds.add(record.id);
snapshot.push(record);
}
}
@@ -2204,17 +2239,17 @@ function endpoint(name, ...args) {
Object.defineProperty(exports, "__esModule", {
value: true
});
/**
* Kinto server error code descriptors.
* @type {Object}
*/
-exports.default = {
+const ERROR_CODES = {
104: "Missing Authorization Token",
105: "Invalid Authorization Token",
106: "Request body was not valid JSON",
107: "Invalid request parameter",
108: "Missing request parameter",
109: "Invalid posted data",
110: "Invalid Token / id",
111: "Missing Token / id",
@@ -2226,34 +2261,112 @@ exports.default = {
117: "Client has sent too many requests",
121: "Resource access is forbidden for this user",
122: "Another resource violates constraint",
201: "Service Temporary unavailable due to high load",
202: "Service deprecated",
999: "Internal Server Error"
};
+exports.default = ERROR_CODES;
+let NetworkTimeoutError = class NetworkTimeoutError extends Error {
+ constructor(url, options) {
+ super(`Timeout while trying to access ${url} with ${JSON.stringify(options)}`);
+
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, NetworkTimeoutError);
+ }
+
+ this.url = url;
+ this.options = options;
+ }
+};
+let UnparseableResponseError = class UnparseableResponseError extends Error {
+ constructor(response, body, error) {
+ const { status } = response;
+
+ super(`Response from server unparseable (HTTP ${status || 0}; ${error}): ${body}`);
+
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, UnparseableResponseError);
+ }
+
+ this.status = status;
+ this.response = response;
+ this.stack = error.stack;
+ this.error = error;
+ }
+};
+
+/**
+ * "Error" subclass representing a >=400 response from the server.
+ *
+ * Whether or not this is an error depends on your application.
+ *
+ * The `json` field can be undefined if the server responded with an
+ * empty response body. This shouldn't generally happen. Most "bad"
+ * responses come with a JSON error description, or (if they're
+ * fronted by a CDN or nginx or something) occasionally non-JSON
+ * responses (which become UnparseableResponseErrors, above).
+ */
+
+let ServerResponse = class ServerResponse extends Error {
+ constructor(response, json) {
+ const { status } = response;
+ let { statusText } = response;
+ let errnoMsg;
+
+ if (json) {
+ // Try to fill in information from the JSON error.
+ statusText = json.error || statusText;
+
+ // Take errnoMsg from either ERROR_CODES or json.message.
+ if (json.errno && json.errno in ERROR_CODES) {
+ errnoMsg = ERROR_CODES[json.errno];
+ } else if (json.message) {
+ errnoMsg = json.message;
+ }
+
+ // If we had both ERROR_CODES and json.message, and they differ,
+ // combine them.
+ if (errnoMsg && json.message && json.message !== errnoMsg) {
+ errnoMsg += ` (${json.message})`;
+ }
+ }
+
+ let message = `HTTP ${status} ${statusText}`;
+ if (errnoMsg) {
+ message += `: ${errnoMsg}`;
+ }
+
+ super(message.trim());
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this, ServerResponse);
+ }
+
+ this.response = response;
+ this.data = json;
+ }
+};
+exports.NetworkTimeoutError = NetworkTimeoutError;
+exports.ServerResponse = ServerResponse;
+exports.UnparseableResponseError = UnparseableResponseError;
+
},{}],13:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = undefined;
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
var _utils = require("./utils");
var _errors = require("./errors");
-var _errors2 = _interopRequireDefault(_errors);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
/**
* Enhanced HTTP client for the Kinto protocol.
* @private
*/
let HTTP = class HTTP {
/**
* Default HTTP request headers applied to each outgoing request.
*
@@ -2314,17 +2427,17 @@ let HTTP = class HTTP {
timedFetch(url, options) {
let hasTimedout = false;
return new Promise((resolve, reject) => {
// Detect if a request has timed out.
let _timeoutId;
if (this.timeout) {
_timeoutId = setTimeout(() => {
hasTimedout = true;
- reject(new Error("Request timeout."));
+ reject(new _errors.NetworkTimeoutError(url, options));
}, this.timeout);
}
function proceedWithHandler(fn) {
return arg => {
if (!hasTimedout) {
if (_timeoutId) {
clearTimeout(_timeoutId);
}
@@ -2335,62 +2448,39 @@ let HTTP = class HTTP {
fetch(url, options).then(proceedWithHandler(resolve)).catch(proceedWithHandler(reject));
});
}
/**
* @private
*/
async processResponse(response) {
- const { status } = response;
+ const { status, headers } = response;
const text = await response.text();
// Check if we have a body; if so parse it as JSON.
- if (text.length === 0) {
- return this.formatResponse(response, null);
- }
- try {
- return this.formatResponse(response, JSON.parse(text));
- } catch (err) {
- const error = new Error(`HTTP ${status || 0}; ${err}`);
- error.response = response;
- error.stack = err.stack;
- throw error;
+ let json;
+ if (text.length !== 0) {
+ try {
+ json = JSON.parse(text);
+ } catch (err) {
+ throw new _errors.UnparseableResponseError(response, text, err);
+ }
}
- }
-
- /**
- * @private
- */
- formatResponse(response, json) {
- const { status, statusText, headers } = response;
- if (json && status >= 400) {
- let message = `HTTP ${status} ${json.error || ""}: `;
- if (json.errno && json.errno in _errors2.default) {
- const errnoMsg = _errors2.default[json.errno];
- message += errnoMsg;
- if (json.message && json.message !== errnoMsg) {
- message += ` (${json.message})`;
- }
- } else {
- message += statusText || "";
- }
- const error = new Error(message.trim());
- error.response = response;
- error.data = json;
- throw error;
+ if (status >= 400) {
+ throw new _errors.ServerResponse(response, json);
}
return { status, json, headers };
}
/**
* @private
*/
async retry(url, retryAfter, request, options) {
await (0, _utils.delay)(retryAfter);
- return this.request(url, request, _extends({}, options, { retry: options.retry - 1 }));
+ return this.request(url, request, { ...options, retry: options.retry - 1 });
}
/**
* Performs an HTTP request to the Kinto server.
*
* Resolves with an objet containing the following HTTP response properties:
* - `{Number} status` The HTTP status code.
* - `{Object} json` The JSON response body.
@@ -2402,17 +2492,17 @@ let HTTP = class HTTP {
* @param {Object} [request.headers] The request headers object (default: {})
* @param {Object} [options={}] Options for making the
* request
* @param {Number} [options.retry] Number of retries (default: 0)
* @return {Promise}
*/
async request(url, request = { headers: {} }, options = { retry: 0 }) {
// Ensure default request headers are always set
- request.headers = _extends({}, HTTP.DEFAULT_REQUEST_HEADERS, request.headers);
+ request.headers = { ...HTTP.DEFAULT_REQUEST_HEADERS, ...request.headers };
// If a multipart body is provided, remove any custom Content-Type header as
// the fetch() implementation will add the correct one for us.
if (request.body && typeof request.body.append === "function") {
delete request.headers["Content-Type"];
}
request.mode = this.requestMode;
const response = await this.timedFetch(url, request);
@@ -2472,19 +2562,16 @@ let HTTP = class HTTP {
exports.default = HTTP;
},{"./errors":12,"./utils":15}],14:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
exports.createRequest = createRequest;
exports.updateRequest = updateRequest;
exports.jsonPatchPermissionsRequest = jsonPatchPermissionsRequest;
exports.deleteRequest = deleteRequest;
exports.addAttachmentRequest = addAttachmentRequest;
var _utils = require("./utils");
@@ -2509,115 +2596,120 @@ function safeHeader(safe, last_modified)
}
return { "If-None-Match": "*" };
}
/**
* @private
*/
function createRequest(path, { data, permissions }, options = {}) {
- const { headers, safe } = _extends({}, requestDefaults, options);
+ const { headers, safe } = {
+ ...requestDefaults,
+ ...options
+ };
return {
method: data && data.id ? "PUT" : "POST",
path,
- headers: _extends({}, headers, safeHeader(safe)),
+ headers: { ...headers, ...safeHeader(safe) },
body: { data, permissions }
};
}
/**
* @private
*/
function updateRequest(path, { data, permissions }, options = {}) {
- const { headers, safe, patch } = _extends({}, requestDefaults, options);
- const { last_modified } = _extends({}, data, options);
+ const { headers, safe, patch } = { ...requestDefaults, ...options };
+ const { last_modified } = { ...data, ...options };
if (Object.keys((0, _utils.omit)(data, "id", "last_modified")).length === 0) {
data = undefined;
}
return {
method: patch ? "PATCH" : "PUT",
path,
- headers: _extends({}, headers, safeHeader(safe, last_modified)),
+ headers: { ...headers, ...safeHeader(safe, last_modified) },
body: { data, permissions }
};
}
/**
* @private
*/
function jsonPatchPermissionsRequest(path, permissions, opType, options = {}) {
- const { headers, safe, last_modified } = _extends({}, requestDefaults, options);
+ const { headers, safe, last_modified } = { ...requestDefaults, ...options };
const ops = [];
for (const [type, principals] of Object.entries(permissions)) {
for (const principal of principals) {
ops.push({
op: opType,
path: `/permissions/${type}/${principal}`
});
}
}
return {
method: "PATCH",
path,
- headers: _extends({}, headers, safeHeader(safe, last_modified), {
+ headers: {
+ ...headers,
+ ...safeHeader(safe, last_modified),
"Content-Type": "application/json-patch+json"
- }),
+ },
body: ops
};
}
/**
* @private
*/
function deleteRequest(path, options = {}) {
- const { headers, safe, last_modified } = _extends({}, requestDefaults, options);
+ const { headers, safe, last_modified } = {
+ ...requestDefaults,
+ ...options
+ };
if (safe && !last_modified) {
throw new Error("Safe concurrency check requires a last_modified value.");
}
return {
method: "DELETE",
path,
- headers: _extends({}, headers, safeHeader(safe, last_modified))
+ headers: { ...headers, ...safeHeader(safe, last_modified) }
};
}
/**
* @private
*/
function addAttachmentRequest(path, dataURI, { data, permissions } = {}, options = {}) {
- const { headers, safe, gzipped } = _extends({}, requestDefaults, options);
- const { last_modified } = _extends({}, data, options);
+ const { headers, safe, gzipped } = { ...requestDefaults, ...options };
+ const { last_modified } = { ...data, ...options };
const body = { data, permissions };
const formData = (0, _utils.createFormData)(dataURI, body, options);
let customPath = gzipped != null ? customPath = path + "?gzipped=" + (gzipped ? "true" : "false") : path;
return {
method: "POST",
path: customPath,
- headers: _extends({}, headers, safeHeader(safe, last_modified)),
+ headers: { ...headers, ...safeHeader(safe, last_modified) },
body: formData
};
}
},{"./utils":15}],15:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
exports.partition = partition;
exports.delay = delay;
exports.pMap = pMap;
exports.omit = omit;
exports.toDataBody = toDataBody;
exports.qsify = qsify;
exports.checkVersion = checkVersion;
exports.support = support;
@@ -2868,19 +2960,19 @@ function parseDataURL(dataURL) {
if (!match) {
throw new Error(`Invalid data-url: ${String(dataURL).substr(0, 32)}...`);
}
const props = match[1];
const base64 = match[2];
const [type, ...rawParams] = props.split(";");
const params = rawParams.reduce((acc, param) => {
const [key, value] = param.split("=");
- return _extends({}, acc, { [key]: value });
+ return { ...acc, [key]: value };
}, {});
- return _extends({}, params, { type, base64 });
+ return { ...params, type, base64 };
}
/**
* Extracts file information from a data url.
* @param {String} dataURL The data url.
* @return {Object}
*/
function extractFileInfo(dataURL) {