mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-26 06:47:17 +10:00
4480 lines
133 KiB
JavaScript
4480 lines
133 KiB
JavaScript
// version 0.6.0
|
||
(function (global, factory) {
|
||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||
typeof define === 'function' && define.amd ? define(factory) :
|
||
(global.mapboxSdk = factory());
|
||
}(this, (function () { 'use strict';
|
||
|
||
// Like https://github.com/thlorenz/lib/parse-link-header but without any
|
||
// additional dependencies.
|
||
|
||
function parseParam(param) {
|
||
var parts = param.match(/\s*(.+)\s*=\s*"?([^"]+)"?/);
|
||
if (!parts) return null;
|
||
|
||
return {
|
||
key: parts[1],
|
||
value: parts[2]
|
||
};
|
||
}
|
||
|
||
function parseLink(link) {
|
||
var parts = link.match(/<?([^>]*)>(.*)/);
|
||
if (!parts) return null;
|
||
|
||
var linkUrl = parts[1];
|
||
var linkParams = parts[2].split(';');
|
||
var rel = null;
|
||
var parsedLinkParams = linkParams.reduce(function(result, param) {
|
||
var parsed = parseParam(param);
|
||
if (!parsed) return result;
|
||
if (parsed.key === 'rel') {
|
||
if (!rel) {
|
||
rel = parsed.value;
|
||
}
|
||
return result;
|
||
}
|
||
result[parsed.key] = parsed.value;
|
||
return result;
|
||
}, {});
|
||
if (!rel) return null;
|
||
|
||
return {
|
||
url: linkUrl,
|
||
rel: rel,
|
||
params: parsedLinkParams
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Parse a Link header.
|
||
*
|
||
* @param {string} linkHeader
|
||
* @returns {{
|
||
* [string]: {
|
||
* url: string,
|
||
* params: { [string]: string }
|
||
* }
|
||
* }}
|
||
*/
|
||
function parseLinkHeader(linkHeader) {
|
||
if (!linkHeader) return {};
|
||
|
||
return linkHeader.split(/,\s*</).reduce(function(result, link) {
|
||
var parsed = parseLink(link);
|
||
if (!parsed) return result;
|
||
// rel value can be multiple whitespace-separated rels.
|
||
var splitRel = parsed.rel.split(/\s+/);
|
||
splitRel.forEach(function(rel) {
|
||
if (!result[rel]) {
|
||
result[rel] = {
|
||
url: parsed.url,
|
||
params: parsed.params
|
||
};
|
||
}
|
||
});
|
||
return result;
|
||
}, {});
|
||
}
|
||
|
||
var parseLinkHeader_1 = parseLinkHeader;
|
||
|
||
/**
|
||
* A Mapbox API response.
|
||
*
|
||
* @class MapiResponse
|
||
* @property {Object} body - The response body, parsed as JSON.
|
||
* @property {string} rawBody - The raw response body.
|
||
* @property {number} statusCode - The response's status code.
|
||
* @property {Object} headers - The parsed response headers.
|
||
* @property {Object} links - The parsed response links.
|
||
* @property {MapiRequest} request - The response's originating `MapiRequest`.
|
||
*/
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {MapiRequest} request
|
||
* @param {Object} responseData
|
||
* @param {Object} responseData.headers
|
||
* @param {string} responseData.body
|
||
* @param {number} responseData.statusCode
|
||
*/
|
||
function MapiResponse(request, responseData) {
|
||
this.request = request;
|
||
this.headers = responseData.headers;
|
||
this.rawBody = responseData.body;
|
||
this.statusCode = responseData.statusCode;
|
||
try {
|
||
this.body = JSON.parse(responseData.body || '{}');
|
||
} catch (parseError) {
|
||
this.body = responseData.body;
|
||
}
|
||
this.links = parseLinkHeader_1(this.headers.link);
|
||
}
|
||
|
||
/**
|
||
* Check if there is a next page that you can fetch.
|
||
*
|
||
* @returns {boolean}
|
||
*/
|
||
MapiResponse.prototype.hasNextPage = function hasNextPage() {
|
||
return !!this.links.next;
|
||
};
|
||
|
||
/**
|
||
* Create a request for the next page, if there is one.
|
||
* If there is no next page, returns `null`.
|
||
*
|
||
* @returns {MapiRequest | null}
|
||
*/
|
||
MapiResponse.prototype.nextPage = function nextPage() {
|
||
if (!this.hasNextPage()) return null;
|
||
return this.request._extend({
|
||
path: this.links.next.url
|
||
});
|
||
};
|
||
|
||
var mapiResponse = MapiResponse;
|
||
|
||
var constants = {
|
||
API_ORIGIN: 'https://api.mapbox.com',
|
||
EVENT_PROGRESS_DOWNLOAD: 'downloadProgress',
|
||
EVENT_PROGRESS_UPLOAD: 'uploadProgress',
|
||
EVENT_ERROR: 'error',
|
||
EVENT_RESPONSE: 'response',
|
||
ERROR_HTTP: 'HttpError',
|
||
ERROR_REQUEST_ABORTED: 'RequestAbortedError'
|
||
};
|
||
|
||
/**
|
||
* A Mapbox API error.
|
||
*
|
||
* If there's an error during the API transaction,
|
||
* the Promise returned by `MapiRequest`'s [`send`](#send)
|
||
* method should reject with a `MapiError`.
|
||
*
|
||
* @class MapiError
|
||
* @hideconstructor
|
||
* @property {MapiRequest} request - The errored request.
|
||
* @property {string} type - The type of error. Usually this is `'HttpError'`.
|
||
* If the request was aborted, so the error was
|
||
* not sent from the server, the type will be
|
||
* `'RequestAbortedError'`.
|
||
* @property {number} [statusCode] - The numeric status code of
|
||
* the HTTP response.
|
||
* @property {Object | string} [body] - If the server sent a response body,
|
||
* this property exposes that response, parsed as JSON if possible.
|
||
* @property {string} [message] - Whatever message could be derived from the
|
||
* call site and HTTP response.
|
||
*
|
||
* @param {MapiRequest} options.request
|
||
* @param {number} [options.statusCode]
|
||
* @param {string} [options.body]
|
||
* @param {string} [options.message]
|
||
* @param {string} [options.type]
|
||
*/
|
||
function MapiError(options) {
|
||
var errorType = options.type || constants.ERROR_HTTP;
|
||
|
||
var body;
|
||
if (options.body) {
|
||
try {
|
||
body = JSON.parse(options.body);
|
||
} catch (e) {
|
||
body = options.body;
|
||
}
|
||
} else {
|
||
body = null;
|
||
}
|
||
|
||
var message = options.message || null;
|
||
if (!message) {
|
||
if (typeof body === 'string') {
|
||
message = body;
|
||
} else if (body && typeof body.message === 'string') {
|
||
message = body.message;
|
||
} else if (errorType === constants.ERROR_REQUEST_ABORTED) {
|
||
message = 'Request aborted';
|
||
}
|
||
}
|
||
|
||
this.message = message;
|
||
this.type = errorType;
|
||
this.statusCode = options.statusCode || null;
|
||
this.request = options.request;
|
||
this.body = body;
|
||
}
|
||
|
||
var mapiError = MapiError;
|
||
|
||
function parseSingleHeader(raw) {
|
||
var boundary = raw.indexOf(':');
|
||
var name = raw
|
||
.substring(0, boundary)
|
||
.trim()
|
||
.toLowerCase();
|
||
var value = raw.substring(boundary + 1).trim();
|
||
return {
|
||
name: name,
|
||
value: value
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Parse raw headers into an object with lowercase properties.
|
||
* Does not fully parse headings into more complete data structure,
|
||
* as larger libraries might do. Also does not deal with duplicate
|
||
* headers because Node doesn't seem to deal with those well, so
|
||
* we shouldn't let the browser either, for consistency.
|
||
*
|
||
* @param {string} raw
|
||
* @returns {Object}
|
||
*/
|
||
function parseHeaders(raw) {
|
||
var headers = {};
|
||
if (!raw) {
|
||
return headers;
|
||
}
|
||
|
||
raw
|
||
.trim()
|
||
.split(/[\r|\n]+/)
|
||
.forEach(function(rawHeader) {
|
||
var parsed = parseSingleHeader(rawHeader);
|
||
headers[parsed.name] = parsed.value;
|
||
});
|
||
|
||
return headers;
|
||
}
|
||
|
||
var parseHeaders_1 = parseHeaders;
|
||
|
||
// Keys are request IDs, values are XHRs.
|
||
var requestsUnderway = {};
|
||
|
||
function browserAbort(request) {
|
||
var xhr = requestsUnderway[request.id];
|
||
if (!xhr) return;
|
||
xhr.abort();
|
||
delete requestsUnderway[request.id];
|
||
}
|
||
|
||
function createResponse(request, xhr) {
|
||
return new mapiResponse(request, {
|
||
body: xhr.response,
|
||
headers: parseHeaders_1(xhr.getAllResponseHeaders()),
|
||
statusCode: xhr.status
|
||
});
|
||
}
|
||
|
||
function normalizeBrowserProgressEvent(event) {
|
||
var total = event.total;
|
||
var transferred = event.loaded;
|
||
var percent = (100 * transferred) / total;
|
||
return {
|
||
total: total,
|
||
transferred: transferred,
|
||
percent: percent
|
||
};
|
||
}
|
||
|
||
function sendRequestXhr(request, xhr) {
|
||
return new Promise(function(resolve, reject) {
|
||
xhr.onprogress = function(event) {
|
||
request.emitter.emit(
|
||
constants.EVENT_PROGRESS_DOWNLOAD,
|
||
normalizeBrowserProgressEvent(event)
|
||
);
|
||
};
|
||
|
||
var file = request.file;
|
||
if (file) {
|
||
xhr.upload.onprogress = function(event) {
|
||
request.emitter.emit(
|
||
constants.EVENT_PROGRESS_UPLOAD,
|
||
normalizeBrowserProgressEvent(event)
|
||
);
|
||
};
|
||
}
|
||
|
||
xhr.onerror = function(error) {
|
||
reject(error);
|
||
};
|
||
|
||
xhr.onabort = function() {
|
||
var mapiError$$1 = new mapiError({
|
||
request: request,
|
||
type: constants.ERROR_REQUEST_ABORTED
|
||
});
|
||
reject(mapiError$$1);
|
||
};
|
||
|
||
xhr.onload = function() {
|
||
delete requestsUnderway[request.id];
|
||
if (xhr.status < 200 || xhr.status >= 400) {
|
||
var mapiError$$1 = new mapiError({
|
||
request: request,
|
||
body: xhr.response,
|
||
statusCode: xhr.status
|
||
});
|
||
reject(mapiError$$1);
|
||
return;
|
||
}
|
||
resolve(xhr);
|
||
};
|
||
|
||
var body = request.body;
|
||
|
||
// matching service needs to send a www-form-urlencoded request
|
||
if (typeof body === 'string') {
|
||
xhr.send(body);
|
||
} else if (body) {
|
||
xhr.send(JSON.stringify(body));
|
||
} else if (file) {
|
||
xhr.send(file);
|
||
} else {
|
||
xhr.send();
|
||
}
|
||
|
||
requestsUnderway[request.id] = xhr;
|
||
}).then(function(xhr) {
|
||
return createResponse(request, xhr);
|
||
});
|
||
}
|
||
|
||
// The accessToken argument gives this function flexibility
|
||
// for Mapbox's internal client.
|
||
function createRequestXhr(request, accessToken) {
|
||
var url = request.url(accessToken);
|
||
var xhr = new window.XMLHttpRequest();
|
||
xhr.open(request.method, url);
|
||
Object.keys(request.headers).forEach(function(key) {
|
||
xhr.setRequestHeader(key, request.headers[key]);
|
||
});
|
||
return xhr;
|
||
}
|
||
|
||
function browserSend(request) {
|
||
return Promise.resolve().then(function() {
|
||
var xhr = createRequestXhr(request, request.client.accessToken);
|
||
return sendRequestXhr(request, xhr);
|
||
});
|
||
}
|
||
|
||
var browserLayer = {
|
||
browserAbort: browserAbort,
|
||
sendRequestXhr: sendRequestXhr,
|
||
browserSend: browserSend,
|
||
createRequestXhr: createRequestXhr
|
||
};
|
||
|
||
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
||
|
||
function createCommonjsModule(fn, module) {
|
||
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
||
}
|
||
|
||
var base64 = createCommonjsModule(function (module, exports) {
|
||
(function(root) {
|
||
|
||
// Detect free variables `exports`.
|
||
var freeExports = exports;
|
||
|
||
// Detect free variable `module`.
|
||
var freeModule = module &&
|
||
module.exports == freeExports && module;
|
||
|
||
// Detect free variable `global`, from Node.js or Browserified code, and use
|
||
// it as `root`.
|
||
var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal;
|
||
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
|
||
root = freeGlobal;
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
var InvalidCharacterError = function(message) {
|
||
this.message = message;
|
||
};
|
||
InvalidCharacterError.prototype = new Error;
|
||
InvalidCharacterError.prototype.name = 'InvalidCharacterError';
|
||
|
||
var error = function(message) {
|
||
// Note: the error messages used throughout this file match those used by
|
||
// the native `atob`/`btoa` implementation in Chromium.
|
||
throw new InvalidCharacterError(message);
|
||
};
|
||
|
||
var TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||
// http://whatwg.org/html/common-microsyntaxes.html#space-character
|
||
var REGEX_SPACE_CHARACTERS = /[\t\n\f\r ]/g;
|
||
|
||
// `decode` is designed to be fully compatible with `atob` as described in the
|
||
// HTML Standard. http://whatwg.org/html/webappapis.html#dom-windowbase64-atob
|
||
// The optimized base64-decoding algorithm used is based on @atk’s excellent
|
||
// implementation. https://gist.github.com/atk/1020396
|
||
var decode = function(input) {
|
||
input = String(input)
|
||
.replace(REGEX_SPACE_CHARACTERS, '');
|
||
var length = input.length;
|
||
if (length % 4 == 0) {
|
||
input = input.replace(/==?$/, '');
|
||
length = input.length;
|
||
}
|
||
if (
|
||
length % 4 == 1 ||
|
||
// http://whatwg.org/C#alphanumeric-ascii-characters
|
||
/[^+a-zA-Z0-9/]/.test(input)
|
||
) {
|
||
error(
|
||
'Invalid character: the string to be decoded is not correctly encoded.'
|
||
);
|
||
}
|
||
var bitCounter = 0;
|
||
var bitStorage;
|
||
var buffer;
|
||
var output = '';
|
||
var position = -1;
|
||
while (++position < length) {
|
||
buffer = TABLE.indexOf(input.charAt(position));
|
||
bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer;
|
||
// Unless this is the first of a group of 4 characters…
|
||
if (bitCounter++ % 4) {
|
||
// …convert the first 8 bits to a single ASCII character.
|
||
output += String.fromCharCode(
|
||
0xFF & bitStorage >> (-2 * bitCounter & 6)
|
||
);
|
||
}
|
||
}
|
||
return output;
|
||
};
|
||
|
||
// `encode` is designed to be fully compatible with `btoa` as described in the
|
||
// HTML Standard: http://whatwg.org/html/webappapis.html#dom-windowbase64-btoa
|
||
var encode = function(input) {
|
||
input = String(input);
|
||
if (/[^\0-\xFF]/.test(input)) {
|
||
// Note: no need to special-case astral symbols here, as surrogates are
|
||
// matched, and the input is supposed to only contain ASCII anyway.
|
||
error(
|
||
'The string to be encoded contains characters outside of the ' +
|
||
'Latin1 range.'
|
||
);
|
||
}
|
||
var padding = input.length % 3;
|
||
var output = '';
|
||
var position = -1;
|
||
var a;
|
||
var b;
|
||
var c;
|
||
var buffer;
|
||
// Make sure any padding is handled outside of the loop.
|
||
var length = input.length - padding;
|
||
|
||
while (++position < length) {
|
||
// Read three bytes, i.e. 24 bits.
|
||
a = input.charCodeAt(position) << 16;
|
||
b = input.charCodeAt(++position) << 8;
|
||
c = input.charCodeAt(++position);
|
||
buffer = a + b + c;
|
||
// Turn the 24 bits into four chunks of 6 bits each, and append the
|
||
// matching character for each of them to the output.
|
||
output += (
|
||
TABLE.charAt(buffer >> 18 & 0x3F) +
|
||
TABLE.charAt(buffer >> 12 & 0x3F) +
|
||
TABLE.charAt(buffer >> 6 & 0x3F) +
|
||
TABLE.charAt(buffer & 0x3F)
|
||
);
|
||
}
|
||
|
||
if (padding == 2) {
|
||
a = input.charCodeAt(position) << 8;
|
||
b = input.charCodeAt(++position);
|
||
buffer = a + b;
|
||
output += (
|
||
TABLE.charAt(buffer >> 10) +
|
||
TABLE.charAt((buffer >> 4) & 0x3F) +
|
||
TABLE.charAt((buffer << 2) & 0x3F) +
|
||
'='
|
||
);
|
||
} else if (padding == 1) {
|
||
buffer = input.charCodeAt(position);
|
||
output += (
|
||
TABLE.charAt(buffer >> 2) +
|
||
TABLE.charAt((buffer << 4) & 0x3F) +
|
||
'=='
|
||
);
|
||
}
|
||
|
||
return output;
|
||
};
|
||
|
||
var base64 = {
|
||
'encode': encode,
|
||
'decode': decode,
|
||
'version': '0.1.0'
|
||
};
|
||
|
||
// Some AMD build optimizers, like r.js, check for specific condition patterns
|
||
// like the following:
|
||
if (freeExports && !freeExports.nodeType) {
|
||
if (freeModule) { // in Node.js or RingoJS v0.8.0+
|
||
freeModule.exports = base64;
|
||
} else { // in Narwhal or RingoJS v0.7.0-
|
||
for (var key in base64) {
|
||
base64.hasOwnProperty(key) && (freeExports[key] = base64[key]);
|
||
}
|
||
}
|
||
} else { // in Rhino or a web browser
|
||
root.base64 = base64;
|
||
}
|
||
|
||
}(commonjsGlobal));
|
||
});
|
||
|
||
var tokenCache = {};
|
||
|
||
function parseToken(token) {
|
||
if (tokenCache[token]) {
|
||
return tokenCache[token];
|
||
}
|
||
|
||
var parts = token.split('.');
|
||
var usage = parts[0];
|
||
var rawPayload = parts[1];
|
||
if (!rawPayload) {
|
||
throw new Error('Invalid token');
|
||
}
|
||
|
||
var parsedPayload = parsePaylod(rawPayload);
|
||
|
||
var result = {
|
||
usage: usage,
|
||
user: parsedPayload.u
|
||
};
|
||
if (has(parsedPayload, 'a')) result.authorization = parsedPayload.a;
|
||
if (has(parsedPayload, 'exp')) result.expires = parsedPayload.exp * 1000;
|
||
if (has(parsedPayload, 'iat')) result.created = parsedPayload.iat * 1000;
|
||
if (has(parsedPayload, 'scopes')) result.scopes = parsedPayload.scopes;
|
||
if (has(parsedPayload, 'client')) result.client = parsedPayload.client;
|
||
if (has(parsedPayload, 'll')) result.lastLogin = parsedPayload.ll;
|
||
if (has(parsedPayload, 'iu')) result.impersonator = parsedPayload.iu;
|
||
|
||
tokenCache[token] = result;
|
||
return result;
|
||
}
|
||
|
||
function parsePaylod(rawPayload) {
|
||
try {
|
||
return JSON.parse(base64.decode(rawPayload));
|
||
} catch (parseError) {
|
||
throw new Error('Invalid token');
|
||
}
|
||
}
|
||
|
||
function has(obj, key) {
|
||
return Object.prototype.hasOwnProperty.call(obj, key);
|
||
}
|
||
|
||
var parseMapboxToken = parseToken;
|
||
|
||
var immutable = extend;
|
||
|
||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||
|
||
function extend() {
|
||
var target = {};
|
||
|
||
for (var i = 0; i < arguments.length; i++) {
|
||
var source = arguments[i];
|
||
|
||
for (var key in source) {
|
||
if (hasOwnProperty.call(source, key)) {
|
||
target[key] = source[key];
|
||
}
|
||
}
|
||
}
|
||
|
||
return target
|
||
}
|
||
|
||
var eventemitter3 = createCommonjsModule(function (module) {
|
||
|
||
var has = Object.prototype.hasOwnProperty
|
||
, prefix = '~';
|
||
|
||
/**
|
||
* Constructor to create a storage for our `EE` objects.
|
||
* An `Events` instance is a plain object whose properties are event names.
|
||
*
|
||
* @constructor
|
||
* @private
|
||
*/
|
||
function Events() {}
|
||
|
||
//
|
||
// We try to not inherit from `Object.prototype`. In some engines creating an
|
||
// instance in this way is faster than calling `Object.create(null)` directly.
|
||
// If `Object.create(null)` is not supported we prefix the event names with a
|
||
// character to make sure that the built-in object properties are not
|
||
// overridden or used as an attack vector.
|
||
//
|
||
if (Object.create) {
|
||
Events.prototype = Object.create(null);
|
||
|
||
//
|
||
// This hack is needed because the `__proto__` property is still inherited in
|
||
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
|
||
//
|
||
if (!new Events().__proto__) prefix = false;
|
||
}
|
||
|
||
/**
|
||
* Representation of a single event listener.
|
||
*
|
||
* @param {Function} fn The listener function.
|
||
* @param {*} context The context to invoke the listener with.
|
||
* @param {Boolean} [once=false] Specify if the listener is a one-time listener.
|
||
* @constructor
|
||
* @private
|
||
*/
|
||
function EE(fn, context, once) {
|
||
this.fn = fn;
|
||
this.context = context;
|
||
this.once = once || false;
|
||
}
|
||
|
||
/**
|
||
* Add a listener for a given event.
|
||
*
|
||
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @param {Function} fn The listener function.
|
||
* @param {*} context The context to invoke the listener with.
|
||
* @param {Boolean} once Specify if the listener is a one-time listener.
|
||
* @returns {EventEmitter}
|
||
* @private
|
||
*/
|
||
function addListener(emitter, event, fn, context, once) {
|
||
if (typeof fn !== 'function') {
|
||
throw new TypeError('The listener must be a function');
|
||
}
|
||
|
||
var listener = new EE(fn, context || emitter, once)
|
||
, evt = prefix ? prefix + event : event;
|
||
|
||
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
|
||
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
|
||
else emitter._events[evt] = [emitter._events[evt], listener];
|
||
|
||
return emitter;
|
||
}
|
||
|
||
/**
|
||
* Clear event by name.
|
||
*
|
||
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
|
||
* @param {(String|Symbol)} evt The Event name.
|
||
* @private
|
||
*/
|
||
function clearEvent(emitter, evt) {
|
||
if (--emitter._eventsCount === 0) emitter._events = new Events();
|
||
else delete emitter._events[evt];
|
||
}
|
||
|
||
/**
|
||
* Minimal `EventEmitter` interface that is molded against the Node.js
|
||
* `EventEmitter` interface.
|
||
*
|
||
* @constructor
|
||
* @public
|
||
*/
|
||
function EventEmitter() {
|
||
this._events = new Events();
|
||
this._eventsCount = 0;
|
||
}
|
||
|
||
/**
|
||
* Return an array listing the events for which the emitter has registered
|
||
* listeners.
|
||
*
|
||
* @returns {Array}
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.eventNames = function eventNames() {
|
||
var names = []
|
||
, events
|
||
, name;
|
||
|
||
if (this._eventsCount === 0) return names;
|
||
|
||
for (name in (events = this._events)) {
|
||
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
|
||
}
|
||
|
||
if (Object.getOwnPropertySymbols) {
|
||
return names.concat(Object.getOwnPropertySymbols(events));
|
||
}
|
||
|
||
return names;
|
||
};
|
||
|
||
/**
|
||
* Return the listeners registered for a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @returns {Array} The registered listeners.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.listeners = function listeners(event) {
|
||
var evt = prefix ? prefix + event : event
|
||
, handlers = this._events[evt];
|
||
|
||
if (!handlers) return [];
|
||
if (handlers.fn) return [handlers.fn];
|
||
|
||
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
|
||
ee[i] = handlers[i].fn;
|
||
}
|
||
|
||
return ee;
|
||
};
|
||
|
||
/**
|
||
* Return the number of listeners listening to a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @returns {Number} The number of listeners.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.listenerCount = function listenerCount(event) {
|
||
var evt = prefix ? prefix + event : event
|
||
, listeners = this._events[evt];
|
||
|
||
if (!listeners) return 0;
|
||
if (listeners.fn) return 1;
|
||
return listeners.length;
|
||
};
|
||
|
||
/**
|
||
* Calls each of the listeners registered for a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @returns {Boolean} `true` if the event had listeners, else `false`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
||
var evt = prefix ? prefix + event : event;
|
||
|
||
if (!this._events[evt]) return false;
|
||
|
||
var listeners = this._events[evt]
|
||
, len = arguments.length
|
||
, args
|
||
, i;
|
||
|
||
if (listeners.fn) {
|
||
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
|
||
|
||
switch (len) {
|
||
case 1: return listeners.fn.call(listeners.context), true;
|
||
case 2: return listeners.fn.call(listeners.context, a1), true;
|
||
case 3: return listeners.fn.call(listeners.context, a1, a2), true;
|
||
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
||
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
||
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
||
}
|
||
|
||
for (i = 1, args = new Array(len -1); i < len; i++) {
|
||
args[i - 1] = arguments[i];
|
||
}
|
||
|
||
listeners.fn.apply(listeners.context, args);
|
||
} else {
|
||
var length = listeners.length
|
||
, j;
|
||
|
||
for (i = 0; i < length; i++) {
|
||
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
|
||
|
||
switch (len) {
|
||
case 1: listeners[i].fn.call(listeners[i].context); break;
|
||
case 2: listeners[i].fn.call(listeners[i].context, a1); break;
|
||
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
|
||
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
|
||
default:
|
||
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
|
||
args[j - 1] = arguments[j];
|
||
}
|
||
|
||
listeners[i].fn.apply(listeners[i].context, args);
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Add a listener for a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @param {Function} fn The listener function.
|
||
* @param {*} [context=this] The context to invoke the listener with.
|
||
* @returns {EventEmitter} `this`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.on = function on(event, fn, context) {
|
||
return addListener(this, event, fn, context, false);
|
||
};
|
||
|
||
/**
|
||
* Add a one-time listener for a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @param {Function} fn The listener function.
|
||
* @param {*} [context=this] The context to invoke the listener with.
|
||
* @returns {EventEmitter} `this`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.once = function once(event, fn, context) {
|
||
return addListener(this, event, fn, context, true);
|
||
};
|
||
|
||
/**
|
||
* Remove the listeners of a given event.
|
||
*
|
||
* @param {(String|Symbol)} event The event name.
|
||
* @param {Function} fn Only remove the listeners that match this function.
|
||
* @param {*} context Only remove the listeners that have this context.
|
||
* @param {Boolean} once Only remove one-time listeners.
|
||
* @returns {EventEmitter} `this`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
||
var evt = prefix ? prefix + event : event;
|
||
|
||
if (!this._events[evt]) return this;
|
||
if (!fn) {
|
||
clearEvent(this, evt);
|
||
return this;
|
||
}
|
||
|
||
var listeners = this._events[evt];
|
||
|
||
if (listeners.fn) {
|
||
if (
|
||
listeners.fn === fn &&
|
||
(!once || listeners.once) &&
|
||
(!context || listeners.context === context)
|
||
) {
|
||
clearEvent(this, evt);
|
||
}
|
||
} else {
|
||
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
|
||
if (
|
||
listeners[i].fn !== fn ||
|
||
(once && !listeners[i].once) ||
|
||
(context && listeners[i].context !== context)
|
||
) {
|
||
events.push(listeners[i]);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Reset the array, or remove it completely if we have no more listeners.
|
||
//
|
||
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
|
||
else clearEvent(this, evt);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Remove all listeners, or those of the specified event.
|
||
*
|
||
* @param {(String|Symbol)} [event] The event name.
|
||
* @returns {EventEmitter} `this`.
|
||
* @public
|
||
*/
|
||
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
||
var evt;
|
||
|
||
if (event) {
|
||
evt = prefix ? prefix + event : event;
|
||
if (this._events[evt]) clearEvent(this, evt);
|
||
} else {
|
||
this._events = new Events();
|
||
this._eventsCount = 0;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
//
|
||
// Alias methods names because people roll like that.
|
||
//
|
||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
||
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
||
|
||
//
|
||
// Expose the prefix.
|
||
//
|
||
EventEmitter.prefixed = prefix;
|
||
|
||
//
|
||
// Allow `EventEmitter` to be imported as module namespace.
|
||
//
|
||
EventEmitter.EventEmitter = EventEmitter;
|
||
|
||
//
|
||
// Expose the module.
|
||
//
|
||
{
|
||
module.exports = EventEmitter;
|
||
}
|
||
});
|
||
|
||
// Encode each item of an array individually. The comma
|
||
// delimiters should not themselves be encoded.
|
||
function encodeArray(arrayValue) {
|
||
return arrayValue.map(encodeURIComponent).join(',');
|
||
}
|
||
|
||
function encodeValue(value) {
|
||
if (Array.isArray(value)) {
|
||
return encodeArray(value);
|
||
}
|
||
return encodeURIComponent(String(value));
|
||
}
|
||
|
||
/**
|
||
* Append a query parameter to a URL.
|
||
*
|
||
* @param {string} url
|
||
* @param {string} key
|
||
* @param {string|number|boolean|Array<*>>} [value] - Provide an array
|
||
* if the value is a list and commas between values need to be
|
||
* preserved, unencoded.
|
||
* @returns {string} - Modified URL.
|
||
*/
|
||
function appendQueryParam(url, key, value) {
|
||
if (value === false || value === null) {
|
||
return url;
|
||
}
|
||
var punctuation = /\?/.test(url) ? '&' : '?';
|
||
var query = encodeURIComponent(key);
|
||
if (value !== undefined && value !== '' && value !== true) {
|
||
query += '=' + encodeValue(value);
|
||
}
|
||
return '' + url + punctuation + query;
|
||
}
|
||
|
||
/**
|
||
* Derive a query string from an object and append it
|
||
* to a URL.
|
||
*
|
||
* @param {string} url
|
||
* @param {Object} [queryObject] - Values should be primitives.
|
||
* @returns {string} - Modified URL.
|
||
*/
|
||
function appendQueryObject(url, queryObject) {
|
||
if (!queryObject) {
|
||
return url;
|
||
}
|
||
|
||
var result = url;
|
||
Object.keys(queryObject).forEach(function(key) {
|
||
var value = queryObject[key];
|
||
if (value === undefined) {
|
||
return;
|
||
}
|
||
if (Array.isArray(value)) {
|
||
value = value
|
||
.filter(function(v) {
|
||
return !!v;
|
||
})
|
||
.join(',');
|
||
}
|
||
result = appendQueryParam(result, key, value);
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Prepend an origin to a URL. If the URL already has an
|
||
* origin, do nothing.
|
||
*
|
||
* @param {string} url
|
||
* @param {string} origin
|
||
* @returns {string} - Modified URL.
|
||
*/
|
||
function prependOrigin(url, origin) {
|
||
if (!origin) {
|
||
return url;
|
||
}
|
||
|
||
if (url.slice(0, 4) === 'http') {
|
||
return url;
|
||
}
|
||
|
||
var delimiter = url[0] === '/' ? '' : '/';
|
||
return '' + origin.replace(/\/$/, '') + delimiter + url;
|
||
}
|
||
|
||
/**
|
||
* Interpolate values into a route with express-style,
|
||
* colon-prefixed route parameters.
|
||
*
|
||
* @param {string} route
|
||
* @param {Object} [params] - Values should be primitives
|
||
* or arrays of primitives. Provide an array if the value
|
||
* is a list and commas between values need to be
|
||
* preserved, unencoded.
|
||
* @returns {string} - Modified URL.
|
||
*/
|
||
function interpolateRouteParams(route, params) {
|
||
if (!params) {
|
||
return route;
|
||
}
|
||
return route.replace(/\/:([a-zA-Z0-9]+)/g, function(_, paramId) {
|
||
var value = params[paramId];
|
||
if (value === undefined) {
|
||
throw new Error('Unspecified route parameter ' + paramId);
|
||
}
|
||
var preppedValue = encodeValue(value);
|
||
return '/' + preppedValue;
|
||
});
|
||
}
|
||
|
||
var urlUtils = {
|
||
appendQueryObject: appendQueryObject,
|
||
appendQueryParam: appendQueryParam,
|
||
prependOrigin: prependOrigin,
|
||
interpolateRouteParams: interpolateRouteParams
|
||
};
|
||
|
||
var requestId = 1;
|
||
|
||
/**
|
||
* A Mapbox API request.
|
||
*
|
||
* Note that creating a `MapiRequest` does *not* send the request automatically.
|
||
* Use the request's `send` method to send it off and get a `Promise`.
|
||
*
|
||
* The `emitter` property is an `EventEmitter` that emits the following events:
|
||
*
|
||
* - `'response'` - Listeners will be called with a `MapiResponse`.
|
||
* - `'error'` - Listeners will be called with a `MapiError`.
|
||
* - `'downloadProgress'` - Listeners will be called with `ProgressEvents`.
|
||
* - `'uploadProgress'` - Listeners will be called with `ProgressEvents`.
|
||
* Upload events are only available when the request includes a file.
|
||
*
|
||
* @class MapiRequest
|
||
* @property {EventEmitter} emitter - An event emitter. See above.
|
||
* @property {MapiClient} client - This request's `MapiClient`.
|
||
* @property {MapiResponse|null} response - If this request has been sent and received
|
||
* a response, the response is available on this property.
|
||
* @property {MapiError|Error|null} error - If this request has been sent and
|
||
* received an error in response, the error is available on this property.
|
||
* @property {boolean} aborted - If the request has been aborted
|
||
* (via [`abort`](#abort)), this property will be `true`.
|
||
* @property {boolean} sent - If the request has been sent, this property will
|
||
* be `true`. You cannot send the same request twice, so if you need to create
|
||
* a new request that is the equivalent of an existing one, use
|
||
* [`clone`](#clone).
|
||
* @property {string} path - The request's path, including colon-prefixed route
|
||
* parameters.
|
||
* @property {string} origin - The request's origin.
|
||
* @property {string} method - The request's HTTP method.
|
||
* @property {Object} query - A query object, which will be transformed into
|
||
* a URL query string.
|
||
* @property {Object} params - A route parameters object, whose values will
|
||
* be interpolated the path.
|
||
* @property {Object} headers - The request's headers.
|
||
* @property {Object|string|null} body - Data to send with the request.
|
||
* If the request has a body, it will also be sent with the header
|
||
* `'Content-Type: application/json'`.
|
||
* @property {Blob|ArrayBuffer|string|ReadStream} file - A file to
|
||
* send with the request. The browser client accepts Blobs and ArrayBuffers;
|
||
* the Node client accepts strings (filepaths) and ReadStreams.
|
||
*/
|
||
|
||
/**
|
||
* @ignore
|
||
* @param {MapiClient} client
|
||
* @param {Object} options
|
||
* @param {string} options.method
|
||
* @param {string} options.path
|
||
* @param {Object} [options.query={}]
|
||
* @param {Object} [options.params={}]
|
||
* @param {string} [options.origin]
|
||
* @param {Object} [options.headers]
|
||
* @param {Object} [options.body=null]
|
||
* @param {Blob|ArrayBuffer|string|ReadStream} [options.file=null]
|
||
*/
|
||
function MapiRequest(client, options) {
|
||
if (!client) {
|
||
throw new Error('MapiRequest requires a client');
|
||
}
|
||
if (!options || !options.path || !options.method) {
|
||
throw new Error(
|
||
'MapiRequest requires an options object with path and method properties'
|
||
);
|
||
}
|
||
|
||
var defaultHeaders = {};
|
||
if (options.body) {
|
||
defaultHeaders['content-type'] = 'application/json';
|
||
}
|
||
|
||
var headersWithDefaults = immutable(defaultHeaders, options.headers);
|
||
|
||
// Disallows duplicate header names of mixed case,
|
||
// e.g. Content-Type and content-type.
|
||
var headers = Object.keys(headersWithDefaults).reduce(function(memo, name) {
|
||
memo[name.toLowerCase()] = headersWithDefaults[name];
|
||
return memo;
|
||
}, {});
|
||
|
||
this.id = requestId++;
|
||
this._options = options;
|
||
|
||
this.emitter = new eventemitter3();
|
||
this.client = client;
|
||
this.response = null;
|
||
this.error = null;
|
||
this.sent = false;
|
||
this.aborted = false;
|
||
this.path = options.path;
|
||
this.method = options.method;
|
||
this.origin = options.origin || client.origin;
|
||
this.query = options.query || {};
|
||
this.params = options.params || {};
|
||
this.body = options.body || null;
|
||
this.file = options.file || null;
|
||
this.headers = headers;
|
||
}
|
||
|
||
/**
|
||
* Get the URL of the request.
|
||
*
|
||
* @param {string} [accessToken] - By default, the access token of the request's
|
||
* client is used.
|
||
* @return {string}
|
||
*/
|
||
MapiRequest.prototype.url = function url(accessToken) {
|
||
var url = urlUtils.prependOrigin(this.path, this.origin);
|
||
url = urlUtils.appendQueryObject(url, this.query);
|
||
var routeParams = this.params;
|
||
if (accessToken) {
|
||
url = urlUtils.appendQueryParam(url, 'access_token', accessToken);
|
||
var accessTokenOwnerId = parseMapboxToken(accessToken).user;
|
||
routeParams = immutable({ ownerId: accessTokenOwnerId }, routeParams);
|
||
}
|
||
url = urlUtils.interpolateRouteParams(url, routeParams);
|
||
return url;
|
||
};
|
||
|
||
/**
|
||
* Send the request. Returns a Promise that resolves with a `MapiResponse`.
|
||
* You probably want to use `response.body`.
|
||
*
|
||
* `send` only retrieves the first page of paginated results. You can get
|
||
* the next page by using the `MapiResponse`'s [`nextPage`](#nextpage)
|
||
* function, or iterate through all pages using [`eachPage`](#eachpage)
|
||
* instead of `send`.
|
||
*
|
||
* @returns {Promise<MapiResponse>}
|
||
*/
|
||
MapiRequest.prototype.send = function send() {
|
||
var self = this;
|
||
|
||
if (self.sent) {
|
||
throw new Error(
|
||
'This request has already been sent. Check the response and error properties. Create a new request with clone().'
|
||
);
|
||
}
|
||
self.sent = true;
|
||
|
||
return self.client.sendRequest(self).then(
|
||
function(response) {
|
||
self.response = response;
|
||
self.emitter.emit(constants.EVENT_RESPONSE, response);
|
||
return response;
|
||
},
|
||
function(error) {
|
||
self.error = error;
|
||
self.emitter.emit(constants.EVENT_ERROR, error);
|
||
throw error;
|
||
}
|
||
);
|
||
};
|
||
|
||
/**
|
||
* Abort the request.
|
||
*
|
||
* Any pending `Promise` returned by [`send`](#send) will be rejected with
|
||
* an error with `type: 'RequestAbortedError'`. If you've created a request
|
||
* that might be aborted, you need to catch and handle such errors.
|
||
*
|
||
* This method will also abort any requests created while fetching subsequent
|
||
* pages via [`eachPage`](#eachpage).
|
||
*
|
||
* If the request has not been sent or has already been aborted, nothing
|
||
* will happen.
|
||
*/
|
||
MapiRequest.prototype.abort = function abort() {
|
||
if (this._nextPageRequest) {
|
||
this._nextPageRequest.abort();
|
||
delete this._nextPageRequest;
|
||
}
|
||
|
||
if (this.response || this.error || this.aborted) return;
|
||
|
||
this.aborted = true;
|
||
this.client.abortRequest(this);
|
||
};
|
||
|
||
/**
|
||
* Invoke a callback for each page of a paginated API response.
|
||
*
|
||
* The callback should have the following signature:
|
||
*
|
||
* ```js
|
||
* (
|
||
* error: MapiError,
|
||
* response: MapiResponse,
|
||
* next: () => void
|
||
* ) => void
|
||
* ```
|
||
*
|
||
* **The next page will not be fetched until you've invoked the
|
||
* `next` callback**, indicating that you're ready for it.
|
||
*
|
||
* @param {Function} callback
|
||
*/
|
||
MapiRequest.prototype.eachPage = function eachPage(callback) {
|
||
var self = this;
|
||
|
||
function handleResponse(response) {
|
||
function getNextPage() {
|
||
delete self._nextPageRequest;
|
||
var nextPageRequest = response.nextPage();
|
||
if (nextPageRequest) {
|
||
self._nextPageRequest = nextPageRequest;
|
||
getPage(nextPageRequest);
|
||
}
|
||
}
|
||
callback(null, response, getNextPage);
|
||
}
|
||
|
||
function handleError(error) {
|
||
callback(error, null, function() {});
|
||
}
|
||
|
||
function getPage(request) {
|
||
request.send().then(handleResponse, handleError);
|
||
}
|
||
getPage(this);
|
||
};
|
||
|
||
/**
|
||
* Clone this request.
|
||
*
|
||
* Each request can only be sent *once*. So if you'd like to send the
|
||
* same request again, clone it and send away.
|
||
*
|
||
* @returns {MapiRequest} - A new `MapiRequest` configured just like this one.
|
||
*/
|
||
MapiRequest.prototype.clone = function clone() {
|
||
return this._extend();
|
||
};
|
||
|
||
/**
|
||
* @ignore
|
||
*/
|
||
MapiRequest.prototype._extend = function _extend(options) {
|
||
var extendedOptions = immutable(this._options, options);
|
||
return new MapiRequest(this.client, extendedOptions);
|
||
};
|
||
|
||
var mapiRequest = MapiRequest;
|
||
|
||
/**
|
||
* A low-level Mapbox API client. Use it to create service clients
|
||
* that share the same configuration.
|
||
*
|
||
* Services and `MapiRequest`s use the underlying `MapiClient` to
|
||
* determine how to create, send, and abort requests in a way
|
||
* that is appropriate to the configuration and environment
|
||
* (Node or the browser).
|
||
*
|
||
* @class MapiClient
|
||
* @property {string} accessToken - The Mapbox access token assigned
|
||
* to this client.
|
||
* @property {string} [origin] - The origin
|
||
* to use for API requests. Defaults to https://api.mapbox.com.
|
||
*/
|
||
|
||
function MapiClient(options) {
|
||
if (!options || !options.accessToken) {
|
||
throw new Error('Cannot create a client without an access token');
|
||
}
|
||
// Try parsing the access token to determine right away if it's valid.
|
||
parseMapboxToken(options.accessToken);
|
||
|
||
this.accessToken = options.accessToken;
|
||
this.origin = options.origin || constants.API_ORIGIN;
|
||
}
|
||
|
||
MapiClient.prototype.createRequest = function createRequest(requestOptions) {
|
||
return new mapiRequest(this, requestOptions);
|
||
};
|
||
|
||
var mapiClient = MapiClient;
|
||
|
||
function BrowserClient(options) {
|
||
mapiClient.call(this, options);
|
||
}
|
||
BrowserClient.prototype = Object.create(mapiClient.prototype);
|
||
BrowserClient.prototype.constructor = BrowserClient;
|
||
|
||
BrowserClient.prototype.sendRequest = browserLayer.browserSend;
|
||
BrowserClient.prototype.abortRequest = browserLayer.browserAbort;
|
||
|
||
/**
|
||
* Create a client for the browser.
|
||
*
|
||
* @param {Object} options
|
||
* @param {string} options.accessToken
|
||
* @param {string} [options.origin]
|
||
* @returns {MapiClient}
|
||
*/
|
||
function createBrowserClient(options) {
|
||
return new BrowserClient(options);
|
||
}
|
||
|
||
var browserClient = createBrowserClient;
|
||
|
||
var toString = Object.prototype.toString;
|
||
|
||
var isPlainObj = function (x) {
|
||
var prototype;
|
||
return toString.call(x) === '[object Object]' && (prototype = Object.getPrototypeOf(x), prototype === null || prototype === Object.getPrototypeOf({}));
|
||
};
|
||
|
||
/**
|
||
* Validators are functions which assert certain type.
|
||
* They can return a string which can then be used
|
||
* to display a helpful error message.
|
||
* They can also return a function for a custom error message.
|
||
*/
|
||
|
||
|
||
|
||
var DEFAULT_ERROR_PATH = 'value';
|
||
var NEWLINE_INDENT = '\n ';
|
||
|
||
var v = {};
|
||
|
||
/**
|
||
* Runners
|
||
*
|
||
* Take root validators and run assertion
|
||
*/
|
||
v.assert = function(rootValidator, options) {
|
||
options = options || {};
|
||
return function(value) {
|
||
var message = validate(rootValidator, value);
|
||
// all good
|
||
if (!message) {
|
||
return;
|
||
}
|
||
|
||
var errorMessage = processMessage(message, options);
|
||
|
||
if (options.apiName) {
|
||
errorMessage = options.apiName + ': ' + errorMessage;
|
||
}
|
||
|
||
throw new Error(errorMessage);
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Higher Order Validators
|
||
*
|
||
* validators which take other validators as input
|
||
* and output a new validator
|
||
*/
|
||
v.shape = function shape(validatorObj) {
|
||
var validators = objectEntries(validatorObj);
|
||
return function shapeValidator(value) {
|
||
var validationResult = validate(v.plainObject, value);
|
||
|
||
if (validationResult) {
|
||
return validationResult;
|
||
}
|
||
|
||
var key, validator;
|
||
var errorMessages = [];
|
||
|
||
for (var i = 0; i < validators.length; i++) {
|
||
key = validators[i].key;
|
||
validator = validators[i].value;
|
||
validationResult = validate(validator, value[key]);
|
||
|
||
if (validationResult) {
|
||
// return [key].concat(validationResult);
|
||
errorMessages.push([key].concat(validationResult));
|
||
}
|
||
}
|
||
|
||
if (errorMessages.length < 2) {
|
||
return errorMessages[0];
|
||
}
|
||
|
||
// enumerate all the error messages
|
||
return function(options) {
|
||
errorMessages = errorMessages.map(function(message) {
|
||
var key = message[0];
|
||
var renderedMessage = processMessage(message, options)
|
||
.split('\n')
|
||
.join(NEWLINE_INDENT); // indents any inner nesting
|
||
return '- ' + key + ': ' + renderedMessage;
|
||
});
|
||
|
||
var objectId = options.path.join('.');
|
||
var ofPhrase = objectId === DEFAULT_ERROR_PATH ? '' : ' of ' + objectId;
|
||
|
||
return (
|
||
'The following properties' +
|
||
ofPhrase +
|
||
' have invalid values:' +
|
||
NEWLINE_INDENT +
|
||
errorMessages.join(NEWLINE_INDENT)
|
||
);
|
||
};
|
||
};
|
||
};
|
||
|
||
v.strictShape = function strictShape(validatorObj) {
|
||
var shapeValidator = v.shape(validatorObj);
|
||
return function strictShapeValidator(value) {
|
||
var shapeResult = shapeValidator(value);
|
||
if (shapeResult) {
|
||
return shapeResult;
|
||
}
|
||
|
||
var invalidKeys = Object.keys(value).reduce(function(memo, valueKey) {
|
||
if (validatorObj[valueKey] === undefined) {
|
||
memo.push(valueKey);
|
||
}
|
||
return memo;
|
||
}, []);
|
||
|
||
if (invalidKeys.length !== 0) {
|
||
return function() {
|
||
return 'The following keys are invalid: ' + invalidKeys.join(', ');
|
||
};
|
||
}
|
||
};
|
||
};
|
||
|
||
v.arrayOf = function arrayOf(validator) {
|
||
return createArrayValidator(validator);
|
||
};
|
||
|
||
v.tuple = function tuple() {
|
||
var validators = Array.isArray(arguments[0])
|
||
? arguments[0]
|
||
: Array.prototype.slice.call(arguments);
|
||
return createArrayValidator(validators);
|
||
};
|
||
|
||
// Currently array validation fails when the first invalid item is found.
|
||
function createArrayValidator(validators) {
|
||
var validatingTuple = Array.isArray(validators);
|
||
var getValidator = function(index) {
|
||
if (validatingTuple) {
|
||
return validators[index];
|
||
}
|
||
return validators;
|
||
};
|
||
|
||
return function arrayValidator(value) {
|
||
var validationResult = validate(v.plainArray, value);
|
||
if (validationResult) {
|
||
return validationResult;
|
||
}
|
||
|
||
if (validatingTuple && value.length !== validators.length) {
|
||
return 'an array with ' + validators.length + ' items';
|
||
}
|
||
|
||
for (var i = 0; i < value.length; i++) {
|
||
validationResult = validate(getValidator(i), value[i]);
|
||
if (validationResult) {
|
||
return [i].concat(validationResult);
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
v.required = function required(validator) {
|
||
function requiredValidator(value) {
|
||
if (value == null) {
|
||
return function(options) {
|
||
return formatErrorMessage(
|
||
options,
|
||
isArrayCulprit(options.path)
|
||
? 'cannot be undefined/null.'
|
||
: 'is required.'
|
||
);
|
||
};
|
||
}
|
||
return validator.apply(this, arguments);
|
||
}
|
||
requiredValidator.__required = true;
|
||
|
||
return requiredValidator;
|
||
};
|
||
|
||
v.oneOfType = function oneOfType() {
|
||
var validators = Array.isArray(arguments[0])
|
||
? arguments[0]
|
||
: Array.prototype.slice.call(arguments);
|
||
return function oneOfTypeValidator(value) {
|
||
var messages = validators
|
||
.map(function(validator) {
|
||
return validate(validator, value);
|
||
})
|
||
.filter(Boolean);
|
||
|
||
// If we don't have as many messages as no. of validators,
|
||
// then at least one validator was ok with the value.
|
||
if (messages.length !== validators.length) {
|
||
return;
|
||
}
|
||
|
||
// check primitive type
|
||
if (
|
||
messages.every(function(message) {
|
||
return message.length === 1 && typeof message[0] === 'string';
|
||
})
|
||
) {
|
||
return orList(
|
||
messages.map(function(m) {
|
||
return m[0];
|
||
})
|
||
);
|
||
}
|
||
|
||
// Complex oneOfTypes like
|
||
// `v.oneOftypes(v.shape({name: v.string})`, `v.shape({name: v.number}))`
|
||
// are complex ¯\_(ツ)_/¯. For the current scope only returning the longest message.
|
||
return messages.reduce(function(max, arr) {
|
||
return arr.length > max.length ? arr : max;
|
||
});
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Meta Validators
|
||
* which take options as argument (not validators)
|
||
* and return a new primitive validator
|
||
*/
|
||
v.equal = function equal(compareWith) {
|
||
return function equalValidator(value) {
|
||
if (value !== compareWith) {
|
||
return JSON.stringify(compareWith);
|
||
}
|
||
};
|
||
};
|
||
|
||
v.oneOf = function oneOf() {
|
||
var options = Array.isArray(arguments[0])
|
||
? arguments[0]
|
||
: Array.prototype.slice.call(arguments);
|
||
var validators = options.map(function(value) {
|
||
return v.equal(value);
|
||
});
|
||
|
||
return v.oneOfType.apply(this, validators);
|
||
};
|
||
|
||
v.range = function range(compareWith) {
|
||
var min = compareWith[0];
|
||
var max = compareWith[1];
|
||
return function rangeValidator(value) {
|
||
var validationResult = validate(v.number, value);
|
||
|
||
if (validationResult || value < min || value > max) {
|
||
return 'number between ' + min + ' & ' + max + ' (inclusive)';
|
||
}
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Primitive validators
|
||
*
|
||
* simple validators which return a string or undefined
|
||
*/
|
||
v.any = function any() {
|
||
return;
|
||
};
|
||
|
||
v.boolean = function boolean(value) {
|
||
if (typeof value !== 'boolean') {
|
||
return 'boolean';
|
||
}
|
||
};
|
||
|
||
v.number = function number(value) {
|
||
if (typeof value !== 'number') {
|
||
return 'number';
|
||
}
|
||
};
|
||
|
||
v.plainArray = function plainArray(value) {
|
||
if (!Array.isArray(value)) {
|
||
return 'array';
|
||
}
|
||
};
|
||
|
||
v.plainObject = function plainObject(value) {
|
||
if (!isPlainObj(value)) {
|
||
return 'object';
|
||
}
|
||
};
|
||
|
||
v.string = function string(value) {
|
||
if (typeof value !== 'string') {
|
||
return 'string';
|
||
}
|
||
};
|
||
|
||
v.func = function func(value) {
|
||
if (typeof value !== 'function') {
|
||
return 'function';
|
||
}
|
||
};
|
||
|
||
function validate(validator, value) {
|
||
// assertions are optional by default unless wrapped in v.require
|
||
if (value == null && !validator.hasOwnProperty('__required')) {
|
||
return;
|
||
}
|
||
|
||
var result = validator(value);
|
||
|
||
if (result) {
|
||
return Array.isArray(result) ? result : [result];
|
||
}
|
||
}
|
||
|
||
function processMessage(message, options) {
|
||
// message array follows the convention
|
||
// [...path, result]
|
||
// path is an array of object keys / array indices
|
||
// result is output of the validator
|
||
var len = message.length;
|
||
|
||
var result = message[len - 1];
|
||
var path = message.slice(0, len - 1);
|
||
|
||
if (path.length === 0) {
|
||
path = [DEFAULT_ERROR_PATH];
|
||
}
|
||
options = immutable(options, { path: path });
|
||
|
||
return typeof result === 'function'
|
||
? result(options) // allows customization of result
|
||
: formatErrorMessage(options, prettifyResult(result));
|
||
}
|
||
|
||
function orList(list) {
|
||
if (list.length < 2) {
|
||
return list[0];
|
||
}
|
||
if (list.length === 2) {
|
||
return list.join(' or ');
|
||
}
|
||
return list.slice(0, -1).join(', ') + ', or ' + list.slice(-1);
|
||
}
|
||
|
||
function prettifyResult(result) {
|
||
return 'must be ' + addArticle(result) + '.';
|
||
}
|
||
|
||
function addArticle(nounPhrase) {
|
||
if (/^an? /.test(nounPhrase)) {
|
||
return nounPhrase;
|
||
}
|
||
if (/^[aeiou]/i.test(nounPhrase)) {
|
||
return 'an ' + nounPhrase;
|
||
}
|
||
if (/^[a-z]/i.test(nounPhrase)) {
|
||
return 'a ' + nounPhrase;
|
||
}
|
||
return nounPhrase;
|
||
}
|
||
|
||
function formatErrorMessage(options, prettyResult) {
|
||
var arrayCulprit = isArrayCulprit(options.path);
|
||
var output = options.path.join('.') + ' ' + prettyResult;
|
||
var prepend = arrayCulprit ? 'Item at position ' : '';
|
||
|
||
return prepend + output;
|
||
}
|
||
|
||
function isArrayCulprit(path) {
|
||
return typeof path[path.length - 1] == 'number' || typeof path[0] == 'number';
|
||
}
|
||
|
||
function objectEntries(obj) {
|
||
return Object.keys(obj || {}).map(function(key) {
|
||
return { key: key, value: obj[key] };
|
||
});
|
||
}
|
||
|
||
v.validate = validate;
|
||
v.processMessage = processMessage;
|
||
|
||
var lib = v;
|
||
|
||
function file(value) {
|
||
// If we're in a browser so Blob is available, the file must be that.
|
||
// In Node, however, it could be a filepath or a pipeable (Readable) stream.
|
||
if (typeof window !== 'undefined') {
|
||
if (value instanceof commonjsGlobal.Blob || value instanceof commonjsGlobal.ArrayBuffer) {
|
||
return;
|
||
}
|
||
return 'Blob or ArrayBuffer';
|
||
}
|
||
if (typeof value === 'string' || value.pipe !== undefined) {
|
||
return;
|
||
}
|
||
return 'Filename or Readable stream';
|
||
}
|
||
|
||
function assertShape(validatorObj, apiName) {
|
||
return lib.assert(lib.strictShape(validatorObj), apiName);
|
||
}
|
||
|
||
function date(value) {
|
||
var msg = 'date';
|
||
if (typeof value === 'boolean') {
|
||
return msg;
|
||
}
|
||
try {
|
||
var date = new Date(value);
|
||
if (date.getTime && isNaN(date.getTime())) {
|
||
return msg;
|
||
}
|
||
} catch (e) {
|
||
return msg;
|
||
}
|
||
}
|
||
|
||
function coordinates(value) {
|
||
return lib.tuple(lib.number, lib.number)(value);
|
||
}
|
||
|
||
var validator = immutable(lib, {
|
||
file: file,
|
||
date: date,
|
||
coordinates: coordinates,
|
||
assertShape: assertShape
|
||
});
|
||
|
||
/**
|
||
* Create a new object by picking properties off an existing object.
|
||
* The second param can be overloaded as a callback for
|
||
* more fine grained picking of properties.
|
||
* @param {Object} source
|
||
* @param {Array<string>|function(string, Object):boolean} keys
|
||
* @returns {Object}
|
||
*/
|
||
function pick(source, keys) {
|
||
var filter = function(key, val) {
|
||
return keys.indexOf(key) !== -1 && val !== undefined;
|
||
};
|
||
|
||
if (typeof keys === 'function') {
|
||
filter = keys;
|
||
}
|
||
|
||
return Object.keys(source)
|
||
.filter(function(key) {
|
||
return filter(key, source[key]);
|
||
})
|
||
.reduce(function(result, key) {
|
||
result[key] = source[key];
|
||
return result;
|
||
}, {});
|
||
}
|
||
|
||
var pick_1 = pick;
|
||
|
||
// This will create the environment-appropriate client.
|
||
|
||
|
||
function createServiceFactory(ServicePrototype) {
|
||
return function(clientOrConfig) {
|
||
var client;
|
||
if (mapiClient.prototype.isPrototypeOf(clientOrConfig)) {
|
||
client = clientOrConfig;
|
||
} else {
|
||
client = browserClient(clientOrConfig);
|
||
}
|
||
var service = Object.create(ServicePrototype);
|
||
service.client = client;
|
||
return service;
|
||
};
|
||
}
|
||
|
||
var createServiceFactory_1 = createServiceFactory;
|
||
|
||
/**
|
||
* Datasets API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#datasets).
|
||
*/
|
||
var Datasets = {};
|
||
|
||
/**
|
||
* List datasets in your account.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#list-datasets).
|
||
*
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* datasetsClient.listDatasets()
|
||
* .send()
|
||
* .then(response => {
|
||
* const datasets = response.body;
|
||
* });
|
||
*
|
||
* @example
|
||
* datasetsClient.listDatasets()
|
||
* .eachPage((error, response, next) => {
|
||
* // Handle error or response and call next.
|
||
* });
|
||
*/
|
||
Datasets.listDatasets = function() {
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/datasets/v1/:ownerId'
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Create a new, empty dataset.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#create-a-dataset).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} [config.name]
|
||
* @param {string} [config.description]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* datasetsClient.createDataset({
|
||
* name: 'example',
|
||
* description: 'An example dataset'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const datasetMetadata = response.body;
|
||
* });
|
||
*/
|
||
Datasets.createDataset = function(config) {
|
||
validator.assertShape({
|
||
name: validator.string,
|
||
description: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'POST',
|
||
path: '/datasets/v1/:ownerId',
|
||
body: config
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Get metadata about a dataset.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#retrieve-a-dataset).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.datasetId
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* datasetsClient.getMetadata({
|
||
* datasetId: 'dataset-id'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const datasetMetadata = response.body;
|
||
* })
|
||
*/
|
||
Datasets.getMetadata = function(config) {
|
||
validator.assertShape({
|
||
datasetId: validator.required(validator.string),
|
||
description: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/datasets/v1/:ownerId/:datasetId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Update user-defined properties of a dataset's metadata.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#update-a-dataset).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.datasetId
|
||
* @param {string} [config.name]
|
||
* @param {string} [config.description]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* datasetsClient.updateMetadata({
|
||
* datasetId: 'dataset-id',
|
||
* name: 'foo'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const datasetMetadata = response.body;
|
||
* });
|
||
*/
|
||
Datasets.updateMetadata = function(config) {
|
||
validator.assertShape({
|
||
datasetId: validator.required(validator.string),
|
||
name: validator.string,
|
||
description: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'PATCH',
|
||
path: '/datasets/v1/:ownerId/:datasetId',
|
||
params: pick_1(config, ['datasetId']),
|
||
body: pick_1(config, ['name', 'description'])
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Delete a dataset, including all features it contains.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#delete-a-dataset).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.datasetId
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* datasetsClient.deleteDataset({
|
||
* datasetId: 'dataset-id'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* // Dataset is successfully deleted.
|
||
* });
|
||
*/
|
||
Datasets.deleteDataset = function(config) {
|
||
validator.assertShape({
|
||
datasetId: validator.required(validator.string)
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'DELETE',
|
||
path: '/datasets/v1/:ownerId/:datasetId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
/**
|
||
* List features in a dataset.
|
||
*
|
||
* This endpoint supports pagination. Use `MapiRequest#eachPage` or manually specify
|
||
* the `limit` and `start` options.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#list-features).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.datasetId
|
||
* @param {number} [config.limit] - Only list this number of features.
|
||
* @param {string} [config.start] - The ID of the feature from which the listing should
|
||
* start.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* datasetsClient.listFeatures({
|
||
* datasetId: 'dataset-id'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const features = response.body;
|
||
* });
|
||
*/
|
||
Datasets.listFeatures = function(config) {
|
||
validator.assertShape({
|
||
datasetId: validator.required(validator.string),
|
||
limit: validator.number,
|
||
start: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/datasets/v1/:ownerId/:datasetId/features',
|
||
params: pick_1(config, ['datasetId']),
|
||
query: pick_1(config, ['limit', 'start'])
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Add a feature to a dataset or update an existing one.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#insert-or-update-a-feature).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.datasetId
|
||
* @param {string} config.featureId
|
||
* @param {Object} config.feature - Valid GeoJSON that is not a `FeatureCollection`.
|
||
* If the feature has a top-level `id` property, it must match the `featureId` you specify.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* datasetsClient.putFeature({
|
||
* datasetId: 'dataset-id',
|
||
* featureId: 'null-island',
|
||
* feature: {
|
||
* "type": "Feature",
|
||
* "properties": { "name": "Null Island" },
|
||
* "geometry": {
|
||
* "type": "Point",
|
||
* "coordinates": [0, 0]
|
||
* }
|
||
* }
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const feature = response.body;
|
||
* });
|
||
*/
|
||
Datasets.putFeature = function(config) {
|
||
validator.assertShape({
|
||
datasetId: validator.required(validator.string),
|
||
featureId: validator.required(validator.string),
|
||
feature: validator.required(validator.plainObject)
|
||
})(config);
|
||
|
||
if (
|
||
config.feature.id !== undefined &&
|
||
config.feature.id !== config.featureId
|
||
) {
|
||
throw new Error('featureId must match the id property of the feature');
|
||
}
|
||
|
||
return this.client.createRequest({
|
||
method: 'PUT',
|
||
path: '/datasets/v1/:ownerId/:datasetId/features/:featureId',
|
||
params: pick_1(config, ['datasetId', 'featureId']),
|
||
body: config.feature
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Get a feature in a dataset.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#retrieve-a-feature).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.datasetId
|
||
* @param {string} config.featureId
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* datasetsClient.getFeature({
|
||
* datasetId: 'dataset-id',
|
||
* featureId: 'feature-id'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const feature = response.body;
|
||
* });
|
||
*/
|
||
Datasets.getFeature = function(config) {
|
||
validator.assertShape({
|
||
datasetId: validator.required(validator.string),
|
||
featureId: validator.required(validator.string)
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/datasets/v1/:ownerId/:datasetId/features/:featureId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Delete a feature in a dataset.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#delete-a-feature).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.datasetId
|
||
* @param {string} config.featureId
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* datasetsClient.deleteFeature({
|
||
* datasetId: 'dataset-id',
|
||
* featureId: 'feature-id'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* // Feature is successfully deleted.
|
||
* });
|
||
*/
|
||
Datasets.deleteFeature = function(config) {
|
||
validator.assertShape({
|
||
datasetId: validator.required(validator.string),
|
||
featureId: validator.required(validator.string)
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'DELETE',
|
||
path: '/datasets/v1/:ownerId/:datasetId/features/:featureId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
var datasets = createServiceFactory_1(Datasets);
|
||
|
||
function objectClean(obj) {
|
||
return pick_1(obj, function(_, val) {
|
||
return val != null;
|
||
});
|
||
}
|
||
|
||
var objectClean_1 = objectClean;
|
||
|
||
function objectMap(obj, cb) {
|
||
return Object.keys(obj).reduce(function(result, key) {
|
||
result[key] = cb(key, obj[key]);
|
||
return result;
|
||
}, {});
|
||
}
|
||
|
||
var objectMap_1 = objectMap;
|
||
|
||
/**
|
||
* Stringify all the boolean values in an object, so true becomes "true".
|
||
*
|
||
* @param {Object} obj
|
||
* @returns {Object}
|
||
*/
|
||
function stringifyBoolean(obj) {
|
||
return objectMap_1(obj, function(_, value) {
|
||
return typeof value === 'boolean' ? JSON.stringify(value) : value;
|
||
});
|
||
}
|
||
|
||
var stringifyBooleans = stringifyBoolean;
|
||
|
||
/**
|
||
* Directions API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/navigation/#directions).
|
||
*/
|
||
var Directions = {};
|
||
|
||
/**
|
||
* Get directions.
|
||
*
|
||
* Please read [the full HTTP service documentation](https://www.mapbox.com/api-documentation/navigation/#directions)
|
||
* to understand all of the available options.
|
||
*
|
||
* @param {Object} config
|
||
* @param {'driving-traffic'|'driving'|'walking'|'cycling'} [config.profile="driving"]
|
||
* @param {Array<DirectionsWaypoint>} config.waypoints - An ordered array of [`DirectionsWaypoint`](#directionswaypoint) objects, between 2 and 25 (inclusive).
|
||
* @param {boolean} [config.alternatives=false] - Whether to try to return alternative routes.
|
||
* @param {Array<'duration'|'distance'|'speed'|'congestion'>} [config.annotations] - Specify additional metadata that should be returned.
|
||
* @param {boolean} [config.bannerInstructions=false] - Should be used in conjunction with `steps`.
|
||
* @param {boolean} [config.continueStraight] - Sets the allowed direction of travel when departing intermediate waypoints.
|
||
* @param {string} [config.exclude] - Exclude certain road types from routing. See HTTP service documentation for options.
|
||
* @param {'geojson'|'polyline'|'polyline6'} [config.geometries="polyline"] - Format of the returned geometry.
|
||
* @param {string} [config.language="en"] - Language of returned turn-by-turn text instructions.
|
||
* See options listed in [the HTTP service documentation](https://www.mapbox.com/api-documentation/navigation/#instructions-languages).
|
||
* @param {'simplified'|'full'|'false'} [config.overview="simplified"] - Type of returned overview geometry.
|
||
* @param {boolean} [config.roundaboutExits=false] - Emit insbtructions at roundabout exits.
|
||
* @param {boolean} [config.steps=false] - Whether to return steps and turn-by-turn instructions.
|
||
* @param {boolean} [config.voiceInstructions=false] - Whether or not to return SSML marked-up text for voice guidance along the route.
|
||
* @param {'imperial'|'metric'} [config.voiceUnits="imperial"] - Which type of units to return in the text for voice instructions.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* directionsClient.getDirections({
|
||
* profile: 'driving-traffic',
|
||
* waypoints: [
|
||
* {
|
||
* coordinates: [13.4301, 52.5109],
|
||
* approach: 'unrestricted'
|
||
* },
|
||
* {
|
||
* coordinates: [13.4265, 52.508]
|
||
* },
|
||
* {
|
||
* coordinates: [13.4194, 52.5072],
|
||
* bearing: [100, 60]
|
||
* }
|
||
* ]
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const directions = response.body;
|
||
* });
|
||
*/
|
||
Directions.getDirections = function(config) {
|
||
validator.assertShape({
|
||
profile: validator.oneOf('driving-traffic', 'driving', 'walking', 'cycling'),
|
||
waypoints: validator.required(
|
||
validator.arrayOf(
|
||
validator.shape({
|
||
coordinates: validator.required(validator.coordinates),
|
||
approach: validator.oneOf('unrestricted', 'curb'),
|
||
bearing: validator.arrayOf(validator.range([0, 360])),
|
||
radius: validator.oneOfType(validator.number, validator.equal('unlimited')),
|
||
waypointName: validator.string
|
||
})
|
||
)
|
||
),
|
||
alternatives: validator.boolean,
|
||
annotations: validator.arrayOf(
|
||
validator.oneOf('duration', 'distance', 'speed', 'congestion')
|
||
),
|
||
bannerInstructions: validator.boolean,
|
||
continueStraight: validator.boolean,
|
||
exclude: validator.string,
|
||
geometries: validator.string,
|
||
language: validator.string,
|
||
overview: validator.string,
|
||
roundaboutExits: validator.boolean,
|
||
steps: validator.boolean,
|
||
voiceInstructions: validator.boolean,
|
||
voiceUnits: validator.string
|
||
})(config);
|
||
|
||
config.profile = config.profile || 'driving';
|
||
|
||
var path = {
|
||
coordinates: [],
|
||
approach: [],
|
||
bearing: [],
|
||
radius: [],
|
||
waypointName: []
|
||
};
|
||
|
||
var waypointCount = config.waypoints.length;
|
||
if (waypointCount < 2 || waypointCount > 25) {
|
||
throw new Error(
|
||
'waypoints must include between 2 and 25 DirectionsWaypoints'
|
||
);
|
||
}
|
||
|
||
/**
|
||
* @typedef {Object} DirectionsWaypoint
|
||
* @property {Coordinates} coordinates
|
||
* @property {'unrestricted'|'curb'} [approach="unrestricted"] - Used to indicate how requested routes consider from which side of the road to approach the waypoint.
|
||
* @property {[number, number]} [bearing] - Used to filter the road segment the waypoint will be placed on by direction and dictates the angle of approach.
|
||
* This option should always be used in conjunction with a `radius`. The first value is an angle clockwise from true north between 0 and 360,
|
||
* and the second is the range of degrees the angle can deviate by.
|
||
* @property {number|'unlimited'} [radius] - Maximum distance in meters that the coordinate is allowed to move when snapped to a nearby road segment.
|
||
* @property {string} [waypointName] - Custom name for the waypoint used for the arrival instruction in banners and voice instructions.
|
||
*/
|
||
config.waypoints.forEach(function(waypoint) {
|
||
path.coordinates.push(
|
||
waypoint.coordinates[0] + ',' + waypoint.coordinates[1]
|
||
);
|
||
|
||
// join props which come in pairs
|
||
['bearing'].forEach(function(prop) {
|
||
if (waypoint.hasOwnProperty(prop) && waypoint[prop] != null) {
|
||
waypoint[prop] = waypoint[prop].join(',');
|
||
}
|
||
});
|
||
|
||
['approach', 'bearing', 'radius', 'waypointName'].forEach(function(prop) {
|
||
if (waypoint.hasOwnProperty(prop) && waypoint[prop] != null) {
|
||
path[prop].push(waypoint[prop]);
|
||
} else {
|
||
path[prop].push('');
|
||
}
|
||
});
|
||
});
|
||
|
||
['approach', 'bearing', 'radius', 'waypointName'].forEach(function(prop) {
|
||
// avoid sending params which are all `;`
|
||
if (
|
||
path[prop].every(function(char) {
|
||
return char === '';
|
||
})
|
||
) {
|
||
delete path[prop];
|
||
} else {
|
||
path[prop] = path[prop].join(';');
|
||
}
|
||
});
|
||
|
||
var query = stringifyBooleans({
|
||
alternatives: config.alternatives,
|
||
annotations: config.annotations,
|
||
banner_instructions: config.bannerInstructions,
|
||
continue_straight: config.continueStraight,
|
||
exclude: config.exclude,
|
||
geometries: config.geometries,
|
||
language: config.language,
|
||
overview: config.overview,
|
||
roundabout_exits: config.roundaboutExits,
|
||
steps: config.steps,
|
||
voice_instructions: config.voiceInstructions,
|
||
voice_units: config.voiceUnits,
|
||
approaches: path.approach,
|
||
bearings: path.bearing,
|
||
radiuses: path.radius,
|
||
waypoint_names: path.waypointName
|
||
});
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/directions/v5/mapbox/:profile/:coordinates',
|
||
params: {
|
||
profile: config.profile,
|
||
coordinates: path.coordinates.join(';')
|
||
},
|
||
query: objectClean_1(query)
|
||
});
|
||
};
|
||
|
||
var directions = createServiceFactory_1(Directions);
|
||
|
||
/**
|
||
* Geocoding API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/search/#geocoding).
|
||
*/
|
||
var Geocoding = {};
|
||
|
||
var featureTypes = [
|
||
'country',
|
||
'region',
|
||
'postcode',
|
||
'district',
|
||
'place',
|
||
'locality',
|
||
'neighborhood',
|
||
'address',
|
||
'poi',
|
||
'poi.landmark'
|
||
];
|
||
|
||
/**
|
||
* Search for a place.
|
||
*
|
||
* See the [public documentation](https://www.mapbox.com/api-documentation/search/#forward-geocoding).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.query - A place name.
|
||
* @param {'mapbox.places'|'mapbox.places-permanent'} [config.mode="mapbox.places"] - Either `mapbox.places` for ephemeral geocoding, or `mapbox.places-permanent` for storing results and batch geocoding.
|
||
* @param {Array<string>} [config.countries] - Limits results to the specified countries.
|
||
* Each item in the array should be an [ISO 3166 alpha 2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2).
|
||
* @param {Coordinates} [config.proximity] - Bias local results based on a provided location.
|
||
* @param {Array<'country'|'region'|'postcode'|'district'|'place'|'locality'|'neighborhood'|'address'|'poi'|'poi.landmark'>} [config.types] - Filter results by feature types.
|
||
* @param {boolean} [config.autocomplete=true] - Return autocomplete results or not.
|
||
* @param {BoundingBox} [config.bbox] - Limit results to a bounding box.
|
||
* @param {number} [config.limit=5] - Limit the number of results returned.
|
||
* @param {Array<string>} [config.language] - Specify the language to use for response text and, for forward geocoding, query result weighting.
|
||
* Options are [IETF language tags](https://en.wikipedia.org/wiki/IETF_language_tag) comprised of a mandatory
|
||
* [ISO 639-1 language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) and optionally one or more IETF subtags for country or script.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* geocodingClient.forwardGeocode({
|
||
* query: 'Paris, France',
|
||
* limit: 2
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const match = response.body;
|
||
* });
|
||
*
|
||
* @example
|
||
* // geocoding with proximity
|
||
* geocodingClient.forwardGeocode({
|
||
* query: 'Paris, France',
|
||
* proximity: [-95.4431142, 33.6875431]
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const match = response.body;
|
||
* });
|
||
*
|
||
* // geocoding with countries
|
||
* geocodingClient.forwardGeocode({
|
||
* query: 'Paris, France',
|
||
* countries: ['fr']
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const match = response.body;
|
||
* });
|
||
*
|
||
* // geocoding with bounding box
|
||
* geocodingClient.forwardGeocode({
|
||
* query: 'Paris, France',
|
||
* bbox: [2.14, 48.72, 2.55, 48.96]
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const match = response.body;
|
||
* });
|
||
*/
|
||
Geocoding.forwardGeocode = function(config) {
|
||
validator.assertShape({
|
||
query: validator.required(validator.string),
|
||
mode: validator.oneOf('mapbox.places', 'mapbox.places-permanent'),
|
||
countries: validator.arrayOf(validator.string),
|
||
proximity: validator.coordinates,
|
||
types: validator.arrayOf(validator.oneOf(featureTypes)),
|
||
autocomplete: validator.boolean,
|
||
bbox: validator.arrayOf(validator.number),
|
||
limit: validator.number,
|
||
language: validator.arrayOf(validator.string)
|
||
})(config);
|
||
|
||
config.mode = config.mode || 'mapbox.places';
|
||
|
||
var query = stringifyBooleans(
|
||
immutable(
|
||
{ country: config.countries },
|
||
pick_1(config, [
|
||
'proximity',
|
||
'types',
|
||
'autocomplete',
|
||
'bbox',
|
||
'limit',
|
||
'language'
|
||
])
|
||
)
|
||
);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/geocoding/v5/:mode/:query.json',
|
||
params: pick_1(config, ['mode', 'query']),
|
||
query: query
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Search for places near coordinates.
|
||
*
|
||
* See the [public documentation](https://www.mapbox.com/api-documentation/search/#reverse-geocoding).
|
||
*
|
||
* @param {Object} config
|
||
* @param {Coordinates} config.query - Coordinates at which features will be searched.
|
||
* @param {'mapbox.places'|'mapbox.places-permanent'} [config.mode="mapbox.places"] - Either `mapbox.places` for ephemeral geocoding, or `mapbox.places-permanent` for storing results and batch geocoding.
|
||
* @param {Array<string>} [config.countries] - Limits results to the specified countries.
|
||
* Each item in the array should be an [ISO 3166 alpha 2 country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2).
|
||
* @param {Array<'country'|'region'|'postcode'|'district'|'place'|'locality'|'neighborhood'|'address'|'poi'|'poi.landmark'>} [config.types] - Filter results by feature types.
|
||
* @param {BoundingBox} [config.bbox] - Limit results to a bounding box.
|
||
* @param {number} [config.limit=1] - Limit the number of results returned. If using this option, you must provide a single item for `types`.
|
||
* @param {Array<string>} [config.language] - Specify the language to use for response text and, for forward geocoding, query result weighting.
|
||
* Options are [IETF language tags](https://en.wikipedia.org/wiki/IETF_language_tag) comprised of a mandatory
|
||
* [ISO 639-1 language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) and optionally one or more IETF subtags for country or script.
|
||
* @param {'distance'|'score'} [config.reverseMode='distance'] - Set the factors that are used to sort nearby results.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* geocodingClient.reverseGeocode({
|
||
* query: [-95.4431142, 33.6875431],
|
||
* limit: 2
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* // GeoJSON document with geocoding matches
|
||
* const match = response.body;
|
||
* });
|
||
*/
|
||
Geocoding.reverseGeocode = function(config) {
|
||
validator.assertShape({
|
||
query: validator.required(validator.coordinates),
|
||
mode: validator.oneOf('mapbox.places', 'mapbox.places-permanent'),
|
||
countries: validator.arrayOf(validator.string),
|
||
types: validator.arrayOf(validator.oneOf(featureTypes)),
|
||
bbox: validator.arrayOf(validator.number),
|
||
limit: validator.number,
|
||
language: validator.arrayOf(validator.string),
|
||
reverseMode: validator.oneOf('distance', 'score')
|
||
})(config);
|
||
|
||
config.mode = config.mode || 'mapbox.places';
|
||
|
||
var query = stringifyBooleans(
|
||
immutable(
|
||
{ country: config.countries },
|
||
pick_1(config, [
|
||
'country',
|
||
'types',
|
||
'bbox',
|
||
'limit',
|
||
'language',
|
||
'reverseMode'
|
||
])
|
||
)
|
||
);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/geocoding/v5/:mode/:query.json',
|
||
params: pick_1(config, ['mode', 'query']),
|
||
query: query
|
||
});
|
||
};
|
||
|
||
var geocoding = createServiceFactory_1(Geocoding);
|
||
|
||
/**
|
||
* Map Matching API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/navigation/#map-matching).
|
||
*/
|
||
var MapMatching = {};
|
||
|
||
/**
|
||
* Snap recorded location traces to roads and paths.
|
||
*
|
||
* @param {Object} config
|
||
* @param {Array<MapMatchingPoint>} config.points - An ordered array of [`MapMatchingPoint`](#mapmatchingpoint)s, between 2 and 100 (inclusive).
|
||
* @param {'driving-traffic'|'driving'|'walking'|'cycling'} [config.profile=driving] - A directions profile ID.
|
||
* @param {Array<'duration'|'distance'|'speed'>} [config.annotations] - Specify additional metadata that should be returned.
|
||
* @param {'geojson'|'polyline'|'polyline6'} [config.geometries="polyline"] - Format of the returned geometry.
|
||
* @param {string} [config.language="en"] - Language of returned turn-by-turn text instructions.
|
||
* See [supported languages](https://www.mapbox.com/api-documentation/navigation/#instructions-languages).
|
||
* @param {'simplified'|'full'|'false'} [config.overview="simplified"] - Type of returned overview geometry.
|
||
* @param {boolean} [config.steps=false] - Whether to return steps and turn-by-turn instructions.
|
||
* @param {boolean} [config.tidy=false] - Whether or not to transparently remove clusters and re-sample traces for improved map matching results.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* mapMatchingClient.getMatch({
|
||
* points: [
|
||
* {
|
||
* coordinates: [-117.17283, 32.712041],
|
||
* approach: 'curb'
|
||
* },
|
||
* {
|
||
* coordinates: [-117.17291, 32.712256],
|
||
* isWaypoint: false
|
||
* },
|
||
* {
|
||
* coordinates: [-117.17292, 32.712444]
|
||
* },
|
||
* {
|
||
* coordinates: [-117.172922, 32.71257],
|
||
* waypointName: 'point-a',
|
||
* approach: 'unrestricted'
|
||
* },
|
||
* {
|
||
* coordinates: [-117.172985, 32.7126]
|
||
* },
|
||
* {
|
||
* coordinates: [-117.173143, 32.712597]
|
||
* },
|
||
* {
|
||
* coordinates: [-117.173345, 32.712546]
|
||
* }
|
||
* ],
|
||
* tidy: false,
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const matching = response.body;
|
||
* })
|
||
*/
|
||
MapMatching.getMatch = function(config) {
|
||
validator.assertShape({
|
||
points: validator.required(
|
||
validator.arrayOf(
|
||
validator.shape({
|
||
coordinates: validator.required(validator.coordinates),
|
||
approach: validator.oneOf('unrestricted', 'curb'),
|
||
radius: validator.range([0, 50]),
|
||
isWaypoint: validator.boolean,
|
||
waypointName: validator.string,
|
||
timestamp: validator.date
|
||
})
|
||
)
|
||
),
|
||
profile: validator.oneOf('driving-traffic', 'driving', 'walking', 'cycling'),
|
||
annotations: validator.arrayOf(validator.oneOf('duration', 'distance', 'speed')),
|
||
geometries: validator.oneOf('geojson', 'polyline', 'polyline6'),
|
||
language: validator.string,
|
||
overview: validator.oneOf('full', 'simplified', 'false'),
|
||
steps: validator.boolean,
|
||
tidy: validator.boolean
|
||
})(config);
|
||
|
||
var pointCount = config.points.length;
|
||
if (pointCount < 2 || pointCount > 100) {
|
||
throw new Error('points must include between 2 and 100 MapMatchingPoints');
|
||
}
|
||
|
||
config.profile = config.profile || 'driving';
|
||
|
||
var path = {
|
||
coordinates: [],
|
||
approach: [],
|
||
radius: [],
|
||
isWaypoint: [],
|
||
waypointName: [],
|
||
timestamp: []
|
||
};
|
||
|
||
/**
|
||
* @typedef {Object} MapMatchingPoint
|
||
* @property {Coordinates} coordinates
|
||
* @property {'unrestricted'|'curb'} [approach="unrestricted"] - Used to indicate how requested routes consider from which side of the road to approach a waypoint.
|
||
* @property {number} [radius=5] - A number in meters indicating the assumed precision of the used tracking device.
|
||
* @property {boolean} [isWaypoint=true] - Whether this coordinate is waypoint or not. The first and last coordinates will always be waypoints.
|
||
* @property {string} [waypointName] - Custom name for the waypoint used for the arrival instruction in banners and voice instructions. Will be ignored unless `isWaypoint` is `true`.
|
||
* @property {tring | number | Date} [timestamp] - Datetime corresponding to the coordinate.
|
||
*/
|
||
config.points.forEach(function(obj) {
|
||
path.coordinates.push(obj.coordinates[0] + ',' + obj.coordinates[1]);
|
||
|
||
// isWaypoint
|
||
if (obj.hasOwnProperty('isWaypoint') && obj.isWaypoint != null) {
|
||
path.isWaypoint.push(obj.isWaypoint);
|
||
} else {
|
||
path.isWaypoint.push(true); // default value
|
||
}
|
||
|
||
if (obj.hasOwnProperty('timestamp') && obj.timestamp != null) {
|
||
path.timestamp.push(Number(new Date(obj.timestamp)));
|
||
} else {
|
||
path.timestamp.push('');
|
||
}
|
||
|
||
['approach', 'radius', 'waypointName'].forEach(function(prop) {
|
||
if (obj.hasOwnProperty(prop) && obj[prop] != null) {
|
||
path[prop].push(obj[prop]);
|
||
} else {
|
||
path[prop].push('');
|
||
}
|
||
});
|
||
});
|
||
|
||
['coordinates', 'approach', 'radius', 'waypointName', 'timestamp'].forEach(
|
||
function(prop) {
|
||
// avoid sending params which are all `;`
|
||
if (
|
||
path[prop].every(function(value) {
|
||
return value === '';
|
||
})
|
||
) {
|
||
delete path[prop];
|
||
} else {
|
||
path[prop] = path[prop].join(';');
|
||
}
|
||
}
|
||
);
|
||
|
||
// the api requires the first and last items to be true.
|
||
path.isWaypoint[0] = true;
|
||
path.isWaypoint[path.isWaypoint.length - 1] = true;
|
||
|
||
if (
|
||
path.isWaypoint.every(function(value) {
|
||
return value === true;
|
||
})
|
||
) {
|
||
delete path.isWaypoint;
|
||
} else {
|
||
// the api requires the indexes to be sent
|
||
path.isWaypoint = path.isWaypoint
|
||
.map(function(val, i) {
|
||
return val === true ? i : '';
|
||
})
|
||
.join(';');
|
||
}
|
||
|
||
var body = stringifyBooleans(
|
||
objectClean_1({
|
||
annotations: config.annotations,
|
||
geometries: config.geometries,
|
||
language: config.language,
|
||
overview: config.overview,
|
||
steps: config.steps,
|
||
tidy: config.tidy,
|
||
approaches: path.approach,
|
||
radiuses: path.radius,
|
||
waypoints: path.isWaypoint,
|
||
timestamps: path.timestamp,
|
||
waypoint_names: path.waypointName,
|
||
coordinates: path.coordinates
|
||
})
|
||
);
|
||
|
||
// the matching api expects a form-urlencoded
|
||
// post request.
|
||
return this.client.createRequest({
|
||
method: 'POST',
|
||
path: '/matching/v5/mapbox/:profile',
|
||
params: {
|
||
profile: config.profile
|
||
},
|
||
body: urlUtils.appendQueryObject('', body).substring(1), // need to remove the char`?`
|
||
headers: {
|
||
'content-type': 'application/x-www-form-urlencoded'
|
||
}
|
||
});
|
||
};
|
||
|
||
var mapMatching = createServiceFactory_1(MapMatching);
|
||
|
||
/**
|
||
* Map Matching API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/navigation/#matrix).
|
||
*/
|
||
var Matrix = {};
|
||
|
||
/**
|
||
* Get a duration and/or distance matrix showing travel times and distances between coordinates.
|
||
*
|
||
* @param {Object} config
|
||
* @param {Array<MatrixPoint>} config.points - An ordered array of [`MatrixPoint`](#matrixpoint)s, between 2 and 100 (inclusive).
|
||
* @param {'driving-traffic'|'driving'|'walking'|'cycling'} [config.profile=driving] - A Mapbox Directions routing profile ID.
|
||
* @param {'all'|Array<number>} [config.sources] - Use coordinates with given index as sources.
|
||
* @param {'all'|Array<number>} [config.destinations] - Use coordinates with given index as destinations.
|
||
* @param {Array<'distance'|'duration'>} [config.annotations] - Used to specify resulting matrices.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* matrixClient.getMatrix({
|
||
* points: [
|
||
* {
|
||
* coordinates: [2.2, 1.1]
|
||
* },
|
||
* {
|
||
* coordinates: [2.2, 1.1],
|
||
* approach: 'curb'
|
||
* },
|
||
* {
|
||
* coordinates: [3.2, 1.1]
|
||
* },
|
||
* {
|
||
* coordinates: [4.2, 1.1]
|
||
* }
|
||
* ],
|
||
* profile: 'walking'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const matrix = response.body;
|
||
* });
|
||
*/
|
||
Matrix.getMatrix = function(config) {
|
||
validator.assertShape({
|
||
points: validator.required(
|
||
validator.arrayOf(
|
||
validator.shape({
|
||
coordinates: validator.required(validator.coordinates),
|
||
approach: validator.oneOf('unrestricted', 'curb')
|
||
})
|
||
)
|
||
),
|
||
profile: validator.oneOf('driving-traffic', 'driving', 'walking', 'cycling'),
|
||
annotations: validator.arrayOf(validator.oneOf('duration', 'distance')),
|
||
sources: validator.oneOfType(validator.equal('all'), validator.arrayOf(validator.number)),
|
||
destinations: validator.oneOfType(validator.equal('all'), validator.arrayOf(validator.number))
|
||
})(config);
|
||
|
||
var pointCount = config.points.length;
|
||
if (pointCount < 2 || pointCount > 100) {
|
||
throw new Error('points must include between 2 and 100 MatrixPoints');
|
||
}
|
||
|
||
config.profile = config.profile || 'driving';
|
||
|
||
var path = {
|
||
coordinates: [],
|
||
approach: []
|
||
};
|
||
/**
|
||
* @typedef {Object} MatrixPoint
|
||
* @property {Coordinates} coordinates - `[longitude, latitude]`
|
||
* @property {'unrestricted'|'curb'} [approach="unrestricted"] - Used to indicate how requested routes consider from which side of the road to approach the point.
|
||
*/
|
||
config.points.forEach(function(obj) {
|
||
path.coordinates.push(obj.coordinates[0] + ',' + obj.coordinates[1]);
|
||
|
||
if (obj.hasOwnProperty('approach') && obj.approach != null) {
|
||
path.approach.push(obj.approach);
|
||
} else {
|
||
path.approach.push(''); // default value
|
||
}
|
||
});
|
||
|
||
if (
|
||
path.approach.every(function(value) {
|
||
return value === '';
|
||
})
|
||
) {
|
||
delete path.approach;
|
||
} else {
|
||
path.approach = path.approach.join(';');
|
||
}
|
||
|
||
var query = {
|
||
sources: Array.isArray(config.sources)
|
||
? config.sources.join(';')
|
||
: config.sources,
|
||
destinations: Array.isArray(config.destinations)
|
||
? config.destinations.join(';')
|
||
: config.destinations,
|
||
approaches: path.approach,
|
||
annotations: config.annotations && config.annotations.join(',')
|
||
};
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/directions-matrix/v1/mapbox/:profile/:coordinates',
|
||
params: {
|
||
profile: config.profile,
|
||
coordinates: path.coordinates.join(';')
|
||
},
|
||
query: objectClean_1(query)
|
||
});
|
||
};
|
||
|
||
var matrix = createServiceFactory_1(Matrix);
|
||
|
||
/**
|
||
* Optimization API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/navigation/#optimization).
|
||
*/
|
||
var Optimization = {};
|
||
|
||
/**
|
||
* Get a duration-optimized route.
|
||
*
|
||
* Please read [the full HTTP service documentation](https://www.mapbox.com/api-documentation/navigation/#optimization)
|
||
* to understand all of the available options.
|
||
*
|
||
* @param {Object} config
|
||
* @param {'driving'|'walking'|'cycling'} [config.profile="driving"]
|
||
* @param {Array<OptimizationWaypoint>} config.waypoints - An ordered array of [`OptimizationWaypoint`](#optimizationwaypoint) objects, between 2 and 12 (inclusive).
|
||
* @param {Array<'duration'|'distance'|'speed'>} [config.annotations] - Specify additional metadata that should be returned.
|
||
* @param {'any'|'last'} [config.destination="any"] - Returned route ends at `any` or `last` coordinate.
|
||
* @param {Array<Distribution>} [config.distributions] - An ordered array of [`Distribution`](#distribution) objects, each of which includes a `pickup` and `dropoff` property. `pickup` and `dropoff` properties correspond to an index in the OptimizationWaypoint array.
|
||
* @param {'geojson'|'polyline'|'polyline6'} [config.geometries="polyline"] - Format of the returned geometries.
|
||
* @param {string} [config.language="en"] - Language of returned turn-by-turn text instructions.
|
||
* See options listed in [the HTTP service documentation](https://www.mapbox.com/api-documentation/navigation/#instructions-languages).
|
||
* @param {'simplified'|'full'|'false'} [config.overview="simplified"] - Type of returned overview geometry.
|
||
* @param {boolean} [config.roundtrip=true] - Specifies whether the trip should complete by returning to the first location.
|
||
* @param {'any'|'first'} [config.source="any"] - To begin the route, start either from the first coordinate or let the Optimization API choose.
|
||
* @param {boolean} [config.steps=false] - Whether to return steps and turn-by-turn instructions.
|
||
* @return {MapiRequest}
|
||
*/
|
||
Optimization.getOptimization = function(config) {
|
||
validator.assertShape({
|
||
profile: validator.oneOf('driving', 'walking', 'cycling'),
|
||
waypoints: validator.required(
|
||
validator.arrayOf(
|
||
validator.shape({
|
||
coordinates: validator.required(validator.coordinates),
|
||
approach: validator.oneOf('unrestricted', 'curb'),
|
||
bearing: validator.arrayOf(validator.range([0, 360])),
|
||
radius: validator.oneOfType(validator.number, validator.equal('unlimited'))
|
||
})
|
||
)
|
||
),
|
||
annotations: validator.arrayOf(validator.oneOf('duration', 'distance', 'speed')),
|
||
geometries: validator.oneOf('geojson', 'polyline', 'polyline6'),
|
||
language: validator.string,
|
||
overview: validator.oneOf('simplified', 'full', 'false'),
|
||
roundtrip: validator.boolean,
|
||
steps: validator.boolean,
|
||
source: validator.oneOf('any', 'first'),
|
||
destination: validator.oneOf('any', 'last'),
|
||
distributions: validator.arrayOf(
|
||
validator.shape({
|
||
pickup: validator.number,
|
||
dropoff: validator.number
|
||
})
|
||
)
|
||
})(config);
|
||
|
||
var path = {
|
||
coordinates: [],
|
||
approach: [],
|
||
bearing: [],
|
||
radius: [],
|
||
distributions: []
|
||
};
|
||
|
||
var waypointCount = config.waypoints.length;
|
||
if (waypointCount < 2 || waypointCount > 12) {
|
||
throw new Error(
|
||
'waypoints must include between 2 and 12 OptimizationWaypoints'
|
||
);
|
||
}
|
||
|
||
/**
|
||
* @typedef {Object} OptimizationWaypoint
|
||
* @property {Coordinates} coordinates
|
||
* @property {'unrestricted'|'curb'} [approach="unrestricted"] - Used to indicate how requested routes consider from which side of the road to approach the waypoint.
|
||
* @property {[number, number]} [bearing] - Used to filter the road segment the waypoint will be placed on by direction and dictates the angle of approach.
|
||
* This option should always be used in conjunction with a `radius`. The first value is an angle clockwise from true north between 0 and 360,
|
||
* and the second is the range of degrees the angle can deviate by.
|
||
* @property {number|'unlimited'} [radius] - Maximum distance in meters that the coordinate is allowed to move when snapped to a nearby road segment.
|
||
*/
|
||
config.waypoints.forEach(function(waypoint) {
|
||
path.coordinates.push(
|
||
waypoint.coordinates[0] + ',' + waypoint.coordinates[1]
|
||
);
|
||
|
||
// join props which come in pairs
|
||
['bearing'].forEach(function(prop) {
|
||
if (waypoint.hasOwnProperty(prop) && waypoint[prop] != null) {
|
||
waypoint[prop] = waypoint[prop].join(',');
|
||
}
|
||
});
|
||
|
||
['approach', 'bearing', 'radius'].forEach(function(prop) {
|
||
if (waypoint.hasOwnProperty(prop) && waypoint[prop] != null) {
|
||
path[prop].push(waypoint[prop]);
|
||
} else {
|
||
path[prop].push('');
|
||
}
|
||
});
|
||
});
|
||
|
||
/**
|
||
* @typedef {Object} Distribution
|
||
* @property {number} pickup - Array index of the item containing coordinates for the pick-up location in the OptimizationWaypoint array.
|
||
* @property {number} dropoff - Array index of the item containing coordinates for the drop-off location in the OptimizationWaypoint array.
|
||
*/
|
||
// distributions aren't a property of OptimizationWaypoint, so join them separately
|
||
if (config.distributions) {
|
||
config.distributions.forEach(function(dist) {
|
||
path.distributions.push(dist.pickup + ',' + dist.dropoff);
|
||
});
|
||
}
|
||
|
||
['approach', 'bearing', 'radius', 'distributions'].forEach(function(prop) {
|
||
// avoid sending params which are all `;`
|
||
if (
|
||
path[prop].every(function(char) {
|
||
return char === '';
|
||
})
|
||
) {
|
||
delete path[prop];
|
||
} else {
|
||
path[prop] = path[prop].join(';');
|
||
}
|
||
});
|
||
|
||
var query = stringifyBooleans({
|
||
geometries: config.geometries,
|
||
language: config.language,
|
||
overview: config.overview,
|
||
roundtrip: config.roundtrip,
|
||
steps: config.steps,
|
||
source: config.source,
|
||
destination: config.destination,
|
||
distributions: path.distributions,
|
||
approaches: path.approach,
|
||
bearings: path.bearing,
|
||
radiuses: path.radius
|
||
});
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/optimized-trips/v1/mapbox/:profile/:coordinates',
|
||
params: {
|
||
profile: config.profile || 'driving',
|
||
coordinates: path.coordinates.join(';')
|
||
},
|
||
query: objectClean_1(query)
|
||
});
|
||
};
|
||
|
||
var optimization = createServiceFactory_1(Optimization);
|
||
|
||
var polyline_1 = createCommonjsModule(function (module) {
|
||
|
||
/**
|
||
* Based off of [the offical Google document](https://developers.google.com/maps/documentation/utilities/polylinealgorithm)
|
||
*
|
||
* Some parts from [this implementation](http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/PolylineEncoder.js)
|
||
* by [Mark McClure](http://facstaff.unca.edu/mcmcclur/)
|
||
*
|
||
* @module polyline
|
||
*/
|
||
|
||
var polyline = {};
|
||
|
||
function py2_round(value) {
|
||
// Google's polyline algorithm uses the same rounding strategy as Python 2, which is different from JS for negative values
|
||
return Math.floor(Math.abs(value) + 0.5) * (value >= 0 ? 1 : -1);
|
||
}
|
||
|
||
function encode(current, previous, factor) {
|
||
current = py2_round(current * factor);
|
||
previous = py2_round(previous * factor);
|
||
var coordinate = current - previous;
|
||
coordinate <<= 1;
|
||
if (current - previous < 0) {
|
||
coordinate = ~coordinate;
|
||
}
|
||
var output = '';
|
||
while (coordinate >= 0x20) {
|
||
output += String.fromCharCode((0x20 | (coordinate & 0x1f)) + 63);
|
||
coordinate >>= 5;
|
||
}
|
||
output += String.fromCharCode(coordinate + 63);
|
||
return output;
|
||
}
|
||
|
||
/**
|
||
* Decodes to a [latitude, longitude] coordinates array.
|
||
*
|
||
* This is adapted from the implementation in Project-OSRM.
|
||
*
|
||
* @param {String} str
|
||
* @param {Number} precision
|
||
* @returns {Array}
|
||
*
|
||
* @see https://github.com/Project-OSRM/osrm-frontend/blob/master/WebContent/routing/OSRM.RoutingGeometry.js
|
||
*/
|
||
polyline.decode = function(str, precision) {
|
||
var index = 0,
|
||
lat = 0,
|
||
lng = 0,
|
||
coordinates = [],
|
||
shift = 0,
|
||
result = 0,
|
||
byte = null,
|
||
latitude_change,
|
||
longitude_change,
|
||
factor = Math.pow(10, precision || 5);
|
||
|
||
// Coordinates have variable length when encoded, so just keep
|
||
// track of whether we've hit the end of the string. In each
|
||
// loop iteration, a single coordinate is decoded.
|
||
while (index < str.length) {
|
||
|
||
// Reset shift, result, and byte
|
||
byte = null;
|
||
shift = 0;
|
||
result = 0;
|
||
|
||
do {
|
||
byte = str.charCodeAt(index++) - 63;
|
||
result |= (byte & 0x1f) << shift;
|
||
shift += 5;
|
||
} while (byte >= 0x20);
|
||
|
||
latitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
|
||
|
||
shift = result = 0;
|
||
|
||
do {
|
||
byte = str.charCodeAt(index++) - 63;
|
||
result |= (byte & 0x1f) << shift;
|
||
shift += 5;
|
||
} while (byte >= 0x20);
|
||
|
||
longitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
|
||
|
||
lat += latitude_change;
|
||
lng += longitude_change;
|
||
|
||
coordinates.push([lat / factor, lng / factor]);
|
||
}
|
||
|
||
return coordinates;
|
||
};
|
||
|
||
/**
|
||
* Encodes the given [latitude, longitude] coordinates array.
|
||
*
|
||
* @param {Array.<Array.<Number>>} coordinates
|
||
* @param {Number} precision
|
||
* @returns {String}
|
||
*/
|
||
polyline.encode = function(coordinates, precision) {
|
||
if (!coordinates.length) { return ''; }
|
||
|
||
var factor = Math.pow(10, precision || 5),
|
||
output = encode(coordinates[0][0], 0, factor) + encode(coordinates[0][1], 0, factor);
|
||
|
||
for (var i = 1; i < coordinates.length; i++) {
|
||
var a = coordinates[i], b = coordinates[i - 1];
|
||
output += encode(a[0], b[0], factor);
|
||
output += encode(a[1], b[1], factor);
|
||
}
|
||
|
||
return output;
|
||
};
|
||
|
||
function flipped(coords) {
|
||
var flipped = [];
|
||
for (var i = 0; i < coords.length; i++) {
|
||
flipped.push(coords[i].slice().reverse());
|
||
}
|
||
return flipped;
|
||
}
|
||
|
||
/**
|
||
* Encodes a GeoJSON LineString feature/geometry.
|
||
*
|
||
* @param {Object} geojson
|
||
* @param {Number} precision
|
||
* @returns {String}
|
||
*/
|
||
polyline.fromGeoJSON = function(geojson, precision) {
|
||
if (geojson && geojson.type === 'Feature') {
|
||
geojson = geojson.geometry;
|
||
}
|
||
if (!geojson || geojson.type !== 'LineString') {
|
||
throw new Error('Input must be a GeoJSON LineString');
|
||
}
|
||
return polyline.encode(flipped(geojson.coordinates), precision);
|
||
};
|
||
|
||
/**
|
||
* Decodes to a GeoJSON LineString geometry.
|
||
*
|
||
* @param {String} str
|
||
* @param {Number} precision
|
||
* @returns {Object}
|
||
*/
|
||
polyline.toGeoJSON = function(str, precision) {
|
||
var coords = polyline.decode(str, precision);
|
||
return {
|
||
type: 'LineString',
|
||
coordinates: flipped(coords)
|
||
};
|
||
};
|
||
|
||
if (module.exports) {
|
||
module.exports = polyline;
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Static API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#static).
|
||
*/
|
||
var Static = {};
|
||
|
||
/**
|
||
* Get a static map image.
|
||
*
|
||
* **If you just want the URL for the static map image, create a request
|
||
* and get it's URL with `MapiRequest#url`.** This is what prior versions of the
|
||
* SDK returned.
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.ownerId - The owner of the map style.
|
||
* @param {string} config.styleId - The map's style ID.
|
||
* @param {number} config.width - Width of the image in pixels, between 1 and 1280.
|
||
* @param {number} config.height - Height of the image in pixels, between 1 and 1280.
|
||
* @param {'auto'|Object} config.position - If `"auto"`, the viewport will fit the
|
||
* bounds of the overlay(s). Otherwise, the maps' position is described by an object
|
||
* with the following properties:
|
||
* `coordinates` (required): [`coordinates`](#coordinates) for the center of image.
|
||
* `zoom` (required): Between 0 and 20.
|
||
* `bearing` (optional): Between 0 and 360.
|
||
* `pitch` (optional): Between 0 and 60.
|
||
*
|
||
* @param {Array<Overlay>} [config.overlays] - Overlays should be in z-index
|
||
* order: the first in the array will be on the bottom; the last will be on
|
||
* the top. Overlays are objects that match one of the following types:
|
||
* [`SimpleMarkerOverlay`](#simplemarkeroverlay),
|
||
* [`CustomMarkerOverlay`](#custommarkeroverlay),
|
||
* [`PathOverlay`](#pathoverlay),
|
||
* [`GeoJsonOverlay`](#geojsonoverlay)
|
||
*
|
||
* @param {boolean} [config.highRes=false]
|
||
* @param {string} [config.insertOverlayBeforeLayer] - The ID of the style layer
|
||
* that overlays should be inserted *before*.
|
||
* @param {boolean} [config.attribution=true] - Whether there is attribution
|
||
* on the map image.
|
||
* @param {boolean} [config.logo=true] - Whether there is a Mapbox logo
|
||
* on the map image.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* staticClient.getStaticImage({
|
||
* ownerId: 'mapbox',
|
||
* styleId: 'streets-v11',
|
||
* width: 200,
|
||
* height: 300,
|
||
* position: {
|
||
* coordinates: [12, 13],
|
||
* zoom: 4
|
||
* }
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const image = response.body;
|
||
* });
|
||
*
|
||
* @example
|
||
* staticClient.getStaticImage({
|
||
* ownerId: 'mapbox',
|
||
* styleId: 'streets-v11',
|
||
* width: 200,
|
||
* height: 300,
|
||
* position: {
|
||
* coordinates: [12, 13],
|
||
* zoom: 3
|
||
* },
|
||
* overlays: [
|
||
* // Simple markers.
|
||
* {
|
||
* marker: {
|
||
* coordinates: [12.2, 12.8]
|
||
* }
|
||
* },
|
||
* {
|
||
* marker: {
|
||
* size: 'large',
|
||
* coordinates: [14, 13.2],
|
||
* label: 'm',
|
||
* color: '#000'
|
||
* }
|
||
* },
|
||
* {
|
||
* marker: {
|
||
* coordinates: [15, 15.2],
|
||
* label: 'airport',
|
||
* color: '#ff0000'
|
||
* }
|
||
* },
|
||
* // Custom marker
|
||
* {
|
||
* marker: {
|
||
* coordinates: [10, 11],
|
||
* url: 'https://upload.wikimedia.org/wikipedia/commons/6/6f/0xff_timetracker.png'
|
||
* }
|
||
* }
|
||
* ]
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const image = response.body;
|
||
* });
|
||
*
|
||
* @example
|
||
* // To get the URL instead of the image, create a request
|
||
* // and get its URL without sending it.
|
||
* const request = staticClient
|
||
* .getStaticImage({
|
||
* ownerId: 'mapbox',
|
||
* styleId: 'streets-v11',
|
||
* width: 200,
|
||
* height: 300,
|
||
* position: {
|
||
* coordinates: [12, 13],
|
||
* zoom: 4
|
||
* }
|
||
* });
|
||
* const staticImageUrl = request.url();
|
||
* // Now you can open staticImageUrl in a browser.
|
||
*/
|
||
Static.getStaticImage = function(config) {
|
||
validator.assertShape({
|
||
ownerId: validator.required(validator.string),
|
||
styleId: validator.required(validator.string),
|
||
width: validator.required(validator.range([1, 1280])),
|
||
height: validator.required(validator.range([1, 1280])),
|
||
position: validator.required(
|
||
validator.oneOfType(
|
||
validator.oneOf('auto'),
|
||
validator.strictShape({
|
||
coordinates: validator.required(validator.coordinates),
|
||
zoom: validator.required(validator.range([0, 20])),
|
||
bearing: validator.range([0, 360]),
|
||
pitch: validator.range([0, 60])
|
||
})
|
||
)
|
||
),
|
||
overlays: validator.arrayOf(validator.plainObject),
|
||
highRes: validator.boolean,
|
||
insertOverlayBeforeLayer: validator.string,
|
||
attribution: validator.boolean,
|
||
logo: validator.boolean
|
||
})(config);
|
||
|
||
var encodedOverlay = (config.overlays || [])
|
||
.map(function(overlayItem) {
|
||
if (overlayItem.marker) {
|
||
return encodeMarkerOverlay(overlayItem.marker);
|
||
}
|
||
if (overlayItem.path) {
|
||
return encodePathOverlay(overlayItem.path);
|
||
}
|
||
return encodeGeoJsonOverlay(overlayItem.geoJson);
|
||
})
|
||
.join(',');
|
||
|
||
var encodedPosition = encodePosition(config.position);
|
||
var encodedDimensions = config.width + 'x' + config.height;
|
||
if (config.highRes) {
|
||
encodedDimensions += '@2x';
|
||
}
|
||
|
||
var preEncodedUrlParts = [encodedOverlay, encodedPosition, encodedDimensions]
|
||
.filter(Boolean)
|
||
.join('/');
|
||
|
||
var query = {};
|
||
if (config.attribution !== undefined) {
|
||
query.attribution = String(config.attribution);
|
||
}
|
||
if (config.logo !== undefined) {
|
||
query.logo = String(config.logo);
|
||
}
|
||
if (config.insertOverlayBeforeLayer !== undefined) {
|
||
query.before_layer = config.insertOverlayBeforeLayer;
|
||
}
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/styles/v1/:ownerId/:styleId/static/' + preEncodedUrlParts,
|
||
params: pick_1(config, ['ownerId', 'styleId']),
|
||
query: query
|
||
});
|
||
};
|
||
|
||
function encodePosition(position) {
|
||
if (position === 'auto') return 'auto';
|
||
|
||
return position.coordinates
|
||
.concat([position.zoom, position.bearing, position.pitch])
|
||
.filter(Boolean)
|
||
.join(',');
|
||
}
|
||
|
||
function encodeMarkerOverlay(o) {
|
||
if (o.url) {
|
||
return encodeCustomMarkerOverlay(o);
|
||
}
|
||
return encodeSimpleMarkerOverlay(o);
|
||
}
|
||
|
||
/**
|
||
* A simple marker overlay.
|
||
* @typedef {Object} SimpleMarkerOverlay
|
||
* @property {Object} marker
|
||
* @property {[number, number]} marker.coordinates - `[longitude, latitude]`
|
||
* @property {'large'|'small'} [marker.size='small']
|
||
* @property {string} [marker.label] - Marker symbol. Options are an alphanumeric label `a`
|
||
* through `z`, `0` through `99`, or a valid [Maki](https://www.mapbox.com/maki/)
|
||
* icon. If a letter is requested, it will be rendered in uppercase only.
|
||
* @property {string} [marker.color] - A 3- or 6-digit hexadecimal color code.
|
||
*/
|
||
|
||
function encodeSimpleMarkerOverlay(o) {
|
||
validator.assertShape({
|
||
coordinates: validator.required(validator.coordinates),
|
||
size: validator.oneOf('large', 'small'),
|
||
label: validator.string,
|
||
color: validator.string
|
||
})(o);
|
||
|
||
var result = o.size === 'large' ? 'pin-l' : 'pin-s';
|
||
if (o.label) {
|
||
result += '-' + String(o.label).toLowerCase();
|
||
}
|
||
if (o.color) {
|
||
result += '+' + sanitizeHexColor(o.color);
|
||
}
|
||
result += '(' + o.coordinates.join(',') + ')';
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* A marker overlay with a custom image.
|
||
* @typedef {Object} CustomMarkerOverlay
|
||
* @property {Object} marker
|
||
* @property {[number, number]} marker.coordinates - `[longitude, latitude]`
|
||
* @property {string} marker.url
|
||
*/
|
||
|
||
function encodeCustomMarkerOverlay(o) {
|
||
validator.assertShape({
|
||
coordinates: validator.required(validator.coordinates),
|
||
url: validator.required(validator.string)
|
||
})(o);
|
||
|
||
var result = 'url-' + encodeURIComponent(o.url);
|
||
result += '(' + o.coordinates.join(',') + ')';
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* A stylable line.
|
||
* @typedef {Object} PathOverlay
|
||
* @property {Object} path
|
||
* @property {Array<Coordinates>} path.coordinates - An array of coordinates
|
||
* describing the path.
|
||
* @property {number} [path.strokeWidth]
|
||
* @property {string} [path.strokeColor]
|
||
* @property {number} [path.strokeOpacity] - Must be paired with strokeColor.
|
||
* @property {string} [path.fillColor] - Must be paired with strokeColor.
|
||
* @property {number} [path.fillOpacity] - Must be paired with fillColor.
|
||
*/
|
||
|
||
function encodePathOverlay(o) {
|
||
validator.assertShape({
|
||
coordinates: validator.required(validator.arrayOf(validator.coordinates)),
|
||
strokeWidth: validator.number,
|
||
strokeColor: validator.string,
|
||
strokeOpacity: validator.number,
|
||
fillColor: validator.string,
|
||
fillOpacity: validator.number
|
||
})(o);
|
||
|
||
if (o.strokeOpacity !== undefined && o.strokeColor === undefined) {
|
||
throw new Error('strokeOpacity requires strokeColor');
|
||
}
|
||
if (o.fillColor !== undefined && o.strokeColor === undefined) {
|
||
throw new Error('fillColor requires strokeColor');
|
||
}
|
||
if (o.fillOpacity !== undefined && o.fillColor === undefined) {
|
||
throw new Error('fillOpacity requires fillColor');
|
||
}
|
||
|
||
var result = 'path';
|
||
if (o.strokeWidth) {
|
||
result += '-' + o.strokeWidth;
|
||
}
|
||
if (o.strokeColor) {
|
||
result += '+' + sanitizeHexColor(o.strokeColor);
|
||
}
|
||
if (o.strokeOpacity) {
|
||
result += '-' + o.strokeOpacity;
|
||
}
|
||
if (o.fillColor) {
|
||
result += '+' + sanitizeHexColor(o.fillColor);
|
||
}
|
||
if (o.fillOpacity) {
|
||
result += '-' + o.fillOpacity;
|
||
}
|
||
// polyline expects each coordinate to be in reversed order: [lat, lng]
|
||
var reversedCoordinates = o.coordinates.map(function(c) {
|
||
return c.reverse();
|
||
});
|
||
var encodedPolyline = polyline_1.encode(reversedCoordinates);
|
||
result += '(' + encodeURIComponent(encodedPolyline) + ')';
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* GeoJSON to overlay the map.
|
||
* @typedef {Object} GeoJsonOverlay
|
||
* @property {Object} geoJson - Valid GeoJSON.
|
||
*/
|
||
|
||
function encodeGeoJsonOverlay(o) {
|
||
validator.assert(validator.required(validator.plainObject))(o);
|
||
|
||
return 'geojson(' + encodeURIComponent(JSON.stringify(o)) + ')';
|
||
}
|
||
|
||
function sanitizeHexColor(color) {
|
||
return color.replace(/^#/, '');
|
||
}
|
||
|
||
var _static = createServiceFactory_1(Static);
|
||
|
||
/**
|
||
* Styles API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#styles).
|
||
*/
|
||
var Styles = {};
|
||
|
||
/**
|
||
* Get a style.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#retrieve-a-style).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.styleId
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* stylesClient.getStyle({
|
||
* styleId: 'style-id'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const style = response.body;
|
||
* });
|
||
*/
|
||
Styles.getStyle = function(config) {
|
||
validator.assertShape({
|
||
styleId: validator.required(validator.string),
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/styles/v1/:ownerId/:styleId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Create a style.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#create-a-style).
|
||
*
|
||
* @param {Object} config
|
||
* @param {Object} config.style - Stylesheet JSON object.
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* stylesClient.createStyle({
|
||
* style: {
|
||
* version: 8,
|
||
* name: "My Awesome Style",
|
||
* metadata: {},
|
||
* sources: {},
|
||
* layers: [],
|
||
* glyphs: "mapbox://fonts/{owner}/{fontstack}/{range}.pbf"
|
||
* }
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const style = response.body;
|
||
* });
|
||
*/
|
||
Styles.createStyle = function(config) {
|
||
validator.assertShape({
|
||
style: validator.plainObject,
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'POST',
|
||
path: '/styles/v1/:ownerId',
|
||
params: pick_1(config, ['ownerId']),
|
||
body: config.style
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Update a style.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#update-a-style).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.styleId
|
||
* @param {Object} config.style - Stylesheet JSON object.
|
||
* @param {string | number | Date} [config.lastKnownModification] - Datetime of last
|
||
* known update. Passed as 'If-Unmodified-Since' HTTP header.
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* stylesClient.updateStyle({
|
||
* styleId: 'style-id',
|
||
* style: {
|
||
* version: 8,
|
||
* name: 'My Awesome Style',
|
||
* metadata: {},
|
||
* sources: {},
|
||
* layers: [],
|
||
* glyphs: 'mapbox://fonts/{owner}/{fontstack}/{range}.pbf'
|
||
* }
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const style = response.body;
|
||
* });
|
||
*/
|
||
Styles.updateStyle = function(config) {
|
||
validator.assertShape({
|
||
styleId: validator.required(validator.string),
|
||
style: validator.required(validator.plainObject),
|
||
lastKnownModification: validator.date,
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
var headers = {};
|
||
if (config.lastKnownModification) {
|
||
headers['If-Unmodified-Since'] = new Date(
|
||
config.lastKnownModification
|
||
).toUTCString();
|
||
}
|
||
return this.client.createRequest({
|
||
method: 'PATCH',
|
||
path: '/styles/v1/:ownerId/:styleId',
|
||
params: pick_1(config, ['styleId', 'ownerId']),
|
||
headers: headers,
|
||
body: config.style
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Delete a style.
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.styleId
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* stylesClient.deleteStyle({
|
||
* styleId: 'style-id'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* // delete successful
|
||
* });
|
||
*/
|
||
Styles.deleteStyle = function(config) {
|
||
validator.assertShape({
|
||
styleId: validator.required(validator.string),
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'DELETE',
|
||
path: '/styles/v1/:ownerId/:styleId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
/**
|
||
* List styles in your account.
|
||
*
|
||
* @param {Object} [config]
|
||
* @param {string} [config.start] - The style ID to start at, for paginated results.
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* stylesClient.listStyles()
|
||
* .send()
|
||
* .then(response => {
|
||
* const styles = response.body;
|
||
* });
|
||
*/
|
||
Styles.listStyles = function(config) {
|
||
config = config || {};
|
||
validator.assertShape({
|
||
start: validator.string,
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
var query = {};
|
||
if (config.start) {
|
||
query.start = config.start;
|
||
}
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/styles/v1/:ownerId',
|
||
params: pick_1(config, ['ownerId']),
|
||
query: query
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Add an icon to a style, or update an existing one.
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.styleId
|
||
* @param {string} config.iconId
|
||
* @param {UploadableFile} config.file - An SVG file.
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* stylesClient.putStyleIcon({
|
||
* styleId: 'foo',
|
||
* iconId: 'bar',
|
||
* // The string filename value works in Node.
|
||
* // In the browser, provide a Blob.
|
||
* file: 'path/to/file.svg'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const newSprite = response.body;
|
||
* });
|
||
*/
|
||
Styles.putStyleIcon = function(config) {
|
||
validator.assertShape({
|
||
styleId: validator.required(validator.string),
|
||
iconId: validator.required(validator.string),
|
||
file: validator.file,
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'PUT',
|
||
path: '/styles/v1/:ownerId/:styleId/sprite/:iconId',
|
||
params: pick_1(config, ['ownerId', 'styleId', 'iconId']),
|
||
file: config.file
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Remove an icon from a style.
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.styleId
|
||
* @param {string} config.iconId
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* stylesClient.deleteStyleIcon({
|
||
* styleId: 'foo',
|
||
* iconId: 'bar'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* // delete successful
|
||
* });
|
||
*/
|
||
Styles.deleteStyleIcon = function(config) {
|
||
validator.assertShape({
|
||
styleId: validator.required(validator.string),
|
||
iconId: validator.required(validator.string),
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'DELETE',
|
||
path: '/styles/v1/:ownerId/:styleId/sprite/:iconId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Get a style sprite's image or JSON document.
|
||
*
|
||
* See [the corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#retrieve-a-sprite-image-or-json).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.styleId
|
||
* @param {'json' | 'png'} [config.format="json"]
|
||
* @param {boolean} [config.highRes] - If true, returns spritesheet with 2x
|
||
* resolution.
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* stylesClient.getStyleSprite({
|
||
* format: 'json',
|
||
* styleId: 'foo',
|
||
* highRes: true
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const sprite = response.body;
|
||
* });
|
||
*/
|
||
Styles.getStyleSprite = function(config) {
|
||
validator.assertShape({
|
||
styleId: validator.required(validator.string),
|
||
format: validator.oneOf('json', 'png'),
|
||
highRes: validator.boolean,
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
var format = config.format || 'json';
|
||
var fileName = 'sprite' + (config.highRes ? '@2x' : '') + '.' + format;
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/styles/v1/:ownerId/:styleId/:fileName',
|
||
params: immutable(pick_1(config, ['ownerId', 'styleId']), {
|
||
fileName: fileName
|
||
})
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Get a font glyph range.
|
||
*
|
||
* See [the corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#retrieve-font-glyph-ranges).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string|Array<string>} config.fonts - An array of font names.
|
||
* @param {number} config.start - Character code of the starting glyph.
|
||
* @param {number} config.end - Character code of the last glyph,
|
||
* typically equivalent to`config.start + 255`.
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* stylesClient.getFontGlyphRange({
|
||
* fonts: 'Arial Unicode',
|
||
* start: 0,
|
||
* end: 255
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const glyph = response.body;
|
||
* });
|
||
*/
|
||
Styles.getFontGlyphRange = function(config) {
|
||
validator.assertShape({
|
||
fonts: validator.required(validator.oneOfType(validator.string, validator.arrayOf(validator.string))),
|
||
start: validator.required(validator.number),
|
||
end: validator.required(validator.number),
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
var fileName = config.start + '-' + config.end + '.pbf';
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/fonts/v1/:ownerId/:fontList/:fileName',
|
||
params: immutable(pick_1(config, ['ownerId']), {
|
||
fontList: [].concat(config.fonts),
|
||
fileName: fileName
|
||
})
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Get embeddable HTML displaying a map.
|
||
*
|
||
* See [the corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#request-embeddable-html).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} styleId
|
||
* @param {boolean} [scrollZoom=true] - If `false`, zooming the map by scrolling will
|
||
* be disabled.
|
||
* @param {boolean} [title=false] - If `true`, the map's title and owner is displayed
|
||
* in the upper right corner of the map.
|
||
* @param {ownerId} [ownerId]
|
||
*/
|
||
Styles.getEmbeddableHtml = function(config) {
|
||
validator.assertShape({
|
||
styleId: validator.required(validator.string),
|
||
scrollZoom: validator.boolean,
|
||
title: validator.boolean,
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
var fileName = config.styleId + '.html';
|
||
var query = {};
|
||
if (config.scrollZoom !== undefined) {
|
||
query.zoomwheel = String(config.scrollZoom);
|
||
}
|
||
if (config.title !== undefined) {
|
||
query.title = String(config.title);
|
||
}
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/styles/v1/:ownerId/:fileName',
|
||
params: immutable(pick_1(config, ['ownerId']), {
|
||
fileName: fileName
|
||
}),
|
||
query: query
|
||
});
|
||
};
|
||
|
||
var styles = createServiceFactory_1(Styles);
|
||
|
||
/**
|
||
* Tilequery API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#tilequery).
|
||
*/
|
||
var Tilequery = {};
|
||
|
||
/**
|
||
* List features within a radius of a point on a map (or several maps).
|
||
*
|
||
* @param {Object} config
|
||
* @param {Array<string>} config.mapIds - The maps being queried.
|
||
* If you need to composite multiple layers, provide multiple map IDs.
|
||
* @param {Coordinates} config.coordinates - The longitude and latitude to be queried.
|
||
* @param {number} [config.radius=0] - The approximate distance in meters to query for features.
|
||
* @param {number} [config.limit=5] - The number of features to return, between 1 and 50.
|
||
* @param {boolean} [config.dedupe=true] - Whether or not to deduplicate results.
|
||
* @param {'polygon'|'linestring'|'point'} [config.geometry] - Queries for a specific geometry type.
|
||
* @param {Array<string>} [config.layers] - IDs of vector layers to query.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* tilequeryClient.listFeatures({
|
||
* mapIds: ['mapbox.mapbox-streets-v8'],
|
||
* coordinates: [-122.42901, 37.80633],
|
||
* radius: 10
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const features = response.body;
|
||
* });
|
||
*/
|
||
Tilequery.listFeatures = function(config) {
|
||
validator.assertShape({
|
||
mapIds: validator.required(validator.arrayOf(validator.string)),
|
||
coordinates: validator.required(validator.coordinates),
|
||
radius: validator.number,
|
||
limit: validator.range([1, 50]),
|
||
dedupe: validator.boolean,
|
||
layers: validator.arrayOf(validator.string)
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/v4/:mapIds/tilequery/:coordinates.json',
|
||
params: {
|
||
mapIds: config.mapIds,
|
||
coordinates: config.coordinates
|
||
},
|
||
query: pick_1(config, ['radius', 'limit', 'dedupe', 'layers'])
|
||
});
|
||
};
|
||
|
||
var tilequery = createServiceFactory_1(Tilequery);
|
||
|
||
/**
|
||
* Tilesets API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#tilesets).
|
||
*/
|
||
var Tilesets = {};
|
||
|
||
/**
|
||
* List a user's tilesets.
|
||
*
|
||
* @param {Object} [config]
|
||
* @param {string} [config.ownerId]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* tilesetsClient.listTilesets()
|
||
* .then(response => {
|
||
* const tilesets = response.body;
|
||
* });
|
||
*
|
||
* @example
|
||
* tilesetsClient.listTilesets()
|
||
* .eachPage((error, response, next) => {
|
||
* // Handle error or response and call next.
|
||
* });
|
||
*/
|
||
Tilesets.listTilesets = function(config) {
|
||
validator.assertShape({
|
||
ownerId: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/tilesets/v1/:ownerId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
var tilesets = createServiceFactory_1(Tilesets);
|
||
|
||
/**
|
||
* Tokens API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/accounts/#tokens).
|
||
*/
|
||
var Tokens = {};
|
||
|
||
/**
|
||
* List your access tokens.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/accounts/#list-tokens).
|
||
*
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* tokensClient.listTokens()
|
||
* .send()
|
||
* .then(response => {
|
||
* const tokens = response.body;
|
||
* });
|
||
*/
|
||
Tokens.listTokens = function() {
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/tokens/v2/:ownerId'
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Create a new access token.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/accounts/#create-a-token).
|
||
*
|
||
* @param {Object} [config]
|
||
* @param {string} [config.note]
|
||
* @param {Array<string>} [config.scopes]
|
||
* @param {Array<string>} [config.resources]
|
||
* @param {Array<string>} [config.allowedUrls]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* tokensClient.createToken({
|
||
* note: 'datasets-token',
|
||
* scopes: ['datasets:write', 'datasets:read']
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const token = response.body;
|
||
* });
|
||
*/
|
||
Tokens.createToken = function(config) {
|
||
config = config || {};
|
||
validator.assertShape({
|
||
note: validator.string,
|
||
scopes: validator.arrayOf(validator.string),
|
||
resources: validator.arrayOf(validator.string),
|
||
allowedUrls: validator.arrayOf(validator.string)
|
||
})(config);
|
||
|
||
var body = {};
|
||
body.scopes = config.scopes || [];
|
||
if (config.note !== undefined) {
|
||
body.note = config.note;
|
||
}
|
||
if (config.resources) {
|
||
body.resources = config.resources;
|
||
}
|
||
if (config.allowedUrls) {
|
||
body.allowedUrls = config.allowedUrls;
|
||
}
|
||
|
||
return this.client.createRequest({
|
||
method: 'POST',
|
||
path: '/tokens/v2/:ownerId',
|
||
params: pick_1(config, ['ownerId']),
|
||
body: body
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Create a new temporary access token.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/accounts/#create-a-temporary-token).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.expires
|
||
* @param {Array<string>} config.scopes
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* tokensClient.createTemporaryToken({
|
||
* scopes: ['datasets:write', 'datasets:read']
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const token = response.body;
|
||
* });
|
||
*/
|
||
Tokens.createTemporaryToken = function(config) {
|
||
validator.assertShape({
|
||
expires: validator.required(validator.date),
|
||
scopes: validator.required(validator.arrayOf(validator.string))
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'POST',
|
||
path: '/tokens/v2/:ownerId',
|
||
params: pick_1(config, ['ownerId']),
|
||
body: {
|
||
expires: new Date(config.expires).toISOString(),
|
||
scopes: config.scopes
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Update an access token.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/accounts/#update-a-token).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.tokenId
|
||
* @param {string} [config.note]
|
||
* @param {Array<string>} [config.scopes]
|
||
* @param {Array<string>} [config.resources]
|
||
* @param {Array<string>} [config.allowedUrls]
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* tokensClient.updateToken({
|
||
* tokenId: 'cijucimbe000brbkt48d0dhcx',
|
||
* note: 'datasets-token',
|
||
* scopes: ['datasets:write', 'datasets:read']
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const token = response.body;
|
||
* });
|
||
*/
|
||
Tokens.updateToken = function(config) {
|
||
validator.assertShape({
|
||
tokenId: validator.required(validator.string),
|
||
note: validator.string,
|
||
scopes: validator.arrayOf(validator.string),
|
||
resources: validator.arrayOf(validator.string),
|
||
allowedUrls: validator.arrayOf(validator.string)
|
||
})(config);
|
||
|
||
var body = {};
|
||
if (config.scopes) {
|
||
body.scopes = config.scopes;
|
||
}
|
||
if (config.note !== undefined) {
|
||
body.note = config.note;
|
||
}
|
||
if (config.resources || config.resources === null) {
|
||
body.resources = config.resources;
|
||
}
|
||
if (config.allowedUrls || config.allowedUrls === null) {
|
||
body.allowedUrls = config.allowedUrls;
|
||
}
|
||
|
||
return this.client.createRequest({
|
||
method: 'PATCH',
|
||
path: '/tokens/v2/:ownerId/:tokenId',
|
||
params: pick_1(config, ['ownerId', 'tokenId']),
|
||
body: body
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Get data about the client's access token.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/accounts/#retrieve-a-token).
|
||
*
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* tokensClient.getToken()
|
||
* .send()
|
||
* .then(response => {
|
||
* const token = response.body;
|
||
* });
|
||
*/
|
||
Tokens.getToken = function() {
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/tokens/v2'
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Delete an access token.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/accounts/#delete-a-token).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.tokenId
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* tokensClient.deleteToken({
|
||
* tokenId: 'cijucimbe000brbkt48d0dhcx'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* // Token successfully deleted.
|
||
* });
|
||
*/
|
||
Tokens.deleteToken = function(config) {
|
||
validator.assertShape({
|
||
tokenId: validator.required(validator.string)
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'DELETE',
|
||
path: '/tokens/v2/:ownerId/:tokenId',
|
||
params: pick_1(config, ['ownerId', 'tokenId'])
|
||
});
|
||
};
|
||
|
||
/**
|
||
* List your available scopes. Each item is a metadata
|
||
* object about the scope, not just the string scope.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/accounts/#list-scopes).
|
||
*
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* tokensClient.listScopes()
|
||
* .send()
|
||
* .then(response => {
|
||
* const scopes = response.body;
|
||
* });
|
||
*/
|
||
Tokens.listScopes = function() {
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/scopes/v1/:ownerId'
|
||
});
|
||
};
|
||
|
||
var tokens = createServiceFactory_1(Tokens);
|
||
|
||
/**
|
||
* Uploads API service.
|
||
*
|
||
* Learn more about this service and its responses in
|
||
* [the HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#uploads).
|
||
*/
|
||
var Uploads = {};
|
||
|
||
/**
|
||
* List the statuses of all recent uploads.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#retrieve-recent-upload-statuses).
|
||
*
|
||
* @param {Object} [config]
|
||
* @param {boolean} [config.reverse] - List uploads in chronological order, rather than reverse chronological order.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* uploadsClient.listUploads()
|
||
* .send()
|
||
* .then(response => {
|
||
* const uploads = response.body;
|
||
* });
|
||
*/
|
||
Uploads.listUploads = function(config) {
|
||
validator.assertShape({
|
||
reverse: validator.boolean
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/uploads/v1/:ownerId',
|
||
query: config
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Create S3 credentials.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#retrieve-s3-credentials).
|
||
*
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* const AWS = require('aws-sdk');
|
||
* const getCredentials = () => {
|
||
* return uploadsClient
|
||
* .createUploadCredentials()
|
||
* .send()
|
||
* .then(response => response.body);
|
||
* }
|
||
* const putFileOnS3 = (credentials) => {
|
||
* const s3 = new AWS.S3({
|
||
* accessKeyId: credentials.accessKeyId,
|
||
* secretAccessKey: credentials.secretAccessKey,
|
||
* sessionToken: credentials.sessionToken,
|
||
* region: 'us-east-1'
|
||
* });
|
||
* return s3.putObject({
|
||
* Bucket: credentials.bucket,
|
||
* Key: credentials.key,
|
||
* Body: fs.createReadStream('/path/to/file.mbtiles')
|
||
* }).promise();
|
||
* };
|
||
*
|
||
* getCredentials().then(putFileOnS3);
|
||
*/
|
||
Uploads.createUploadCredentials = function() {
|
||
return this.client.createRequest({
|
||
method: 'POST',
|
||
path: '/uploads/v1/:ownerId/credentials'
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Create an upload.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#create-an-upload).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.mapId - The map ID to create or replace in the format `username.nameoftileset`.
|
||
* Limited to 32 characters (only `-` and `_` special characters allowed; limit does not include username).
|
||
* @param {string} config.url - Either of the following:
|
||
* - HTTPS URL of the S3 object provided by [`createUploadCredentials`](#createuploadcredentials)
|
||
* - The `mapbox://` URL of an existing dataset that you'd like to export to a tileset.
|
||
* This should be in the format `mapbox://datasets/{username}/{datasetId}`.
|
||
* @param {string} [config.tilesetName] - Name for the tileset. Limited to 64 characters.
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* // Response from a call to createUploadCredentials
|
||
* const credentials = {
|
||
* accessKeyId: '{accessKeyId}',
|
||
* bucket: '{bucket}',
|
||
* key: '{key}',
|
||
* secretAccessKey: '{secretAccessKey}',
|
||
* sessionToken: '{sessionToken}',
|
||
* url: '{s3 url}'
|
||
* };
|
||
* uploadsClient.createUpload({
|
||
* mapId: `${myUsername}.${myTileset}`,
|
||
* url: credentials.url
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const upload = response.body;
|
||
* });
|
||
*/
|
||
Uploads.createUpload = function(config) {
|
||
validator.assertShape({
|
||
mapId: validator.required(validator.string),
|
||
url: validator.required(validator.string),
|
||
tilesetName: validator.string
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'POST',
|
||
path: '/uploads/v1/:ownerId',
|
||
body: {
|
||
tileset: config.mapId,
|
||
url: config.url,
|
||
name: config.tilesetName
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Get an upload's status.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#retrieve-upload-status).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.uploadId
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* uploadsClient.getUpload({
|
||
* uploadId: '{upload_id}'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* const status = response.body;
|
||
* });
|
||
*/
|
||
Uploads.getUpload = function(config) {
|
||
validator.assertShape({
|
||
uploadId: validator.required(validator.string)
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'GET',
|
||
path: '/uploads/v1/:ownerId/:uploadId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Delete an upload.
|
||
*
|
||
* See the [corresponding HTTP service documentation](https://www.mapbox.com/api-documentation/maps/#remove-an-upload-status).
|
||
*
|
||
* @param {Object} config
|
||
* @param {string} config.uploadId
|
||
* @return {MapiRequest}
|
||
*
|
||
* @example
|
||
* uploadsClient.deleteUpload({
|
||
* uploadId: '{upload_id}'
|
||
* })
|
||
* .send()
|
||
* .then(response => {
|
||
* // Upload successfully deleted.
|
||
* });
|
||
*/
|
||
Uploads.deleteUpload = function(config) {
|
||
validator.assertShape({
|
||
uploadId: validator.required(validator.string)
|
||
})(config);
|
||
|
||
return this.client.createRequest({
|
||
method: 'DELETE',
|
||
path: '/uploads/v1/:ownerId/:uploadId',
|
||
params: config
|
||
});
|
||
};
|
||
|
||
var uploads = createServiceFactory_1(Uploads);
|
||
|
||
function mapboxSdk(options) {
|
||
var client = browserClient(options);
|
||
|
||
client.datasets = datasets(client);
|
||
client.directions = directions(client);
|
||
client.geocoding = geocoding(client);
|
||
client.mapMatching = mapMatching(client);
|
||
client.matrix = matrix(client);
|
||
client.optimization = optimization(client);
|
||
client.static = _static(client);
|
||
client.styles = styles(client);
|
||
client.tilequery = tilequery(client);
|
||
client.tilesets = tilesets(client);
|
||
client.tokens = tokens(client);
|
||
client.uploads = uploads(client);
|
||
|
||
return client;
|
||
}
|
||
|
||
var bundle = mapboxSdk;
|
||
|
||
return bundle;
|
||
|
||
})));
|