module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
// This is the Parse entry point
// See https://www.parse.com/docs/cloud_code_guide#cloud_code
module.exports = algoliasearch;
// by default parse has no process.env,
// force it down for npm modules compatibility
if (process.env === undefined) {
process.env = {};
}
// a lot of node modules are expecting to find a `global` object,
// this has triggered some bugs
/* global global: true */
global = {};
var debug = __webpack_require__(1)('algoliasearch:parse');
var inherits = __webpack_require__(4);
var AlgoliaSearchServer = __webpack_require__(5);
debug('loaded the Parse client');
function algoliasearch(applicationID, apiKey, opts) {
var cloneDeep = __webpack_require__(15);
opts = cloneDeep(opts || {});
if (opts.protocol === undefined) {
opts.protocol = 'https:';
}
opts.timeouts = opts.timeouts || {
connect: 2 * 1000,
read: 7 * 1000,
write: 30 * 1000
};
opts._setTimeout = _setTimeout;
opts._ua = opts._ua || algoliasearch.ua;
opts._useCache = false;
return new AlgoliaSearchParse(applicationID, apiKey, opts);
}
algoliasearch.version = __webpack_require__(26);
algoliasearch.ua = 'Algolia for Parse ' + algoliasearch.version;
function AlgoliaSearchParse() {
// call AlgoliaSearchServer constructor
AlgoliaSearchServer.apply(this, arguments);
}
inherits(AlgoliaSearchParse, AlgoliaSearchServer);
AlgoliaSearchParse.prototype._request = function(rawUrl, opts) {
/* global Parse */
var clone = __webpack_require__(15);
var promise = new Parse.Promise();
debug('url: %s, opts: %j', rawUrl, opts);
var parseReqOpts = {
url: rawUrl,
headers: clone(opts.headers),
method: opts.method,
success: success,
error: error
};
if (opts.body) {
// parse is proxing our requests and requires us to set a charset. while json is always utf-8
parseReqOpts.headers['content-type'] = 'application/json;charset=utf-8';
parseReqOpts.body = opts.body;
}
Parse.Cloud.httpRequest(parseReqOpts);
function error(res) {
debug('error: %j - %s %j', res, rawUrl, opts);
// we still resolve, bc Parse does not distinguish network errors
// from 400/500 statuses
promise.resolve({
statusCode: res.status,
body: res.data,
headers: res.headers
});
}
function success(res) {
debug('success: %j - %s %j', res, rawUrl, opts);
promise.resolve({
statusCode: res.status,
body: res.data,
headers: res.headers
});
}
return promise;
};
AlgoliaSearchParse.prototype._promise = {
reject: function(val) {
return Parse.Promise.error(val);
},
resolve: function(val) {
return Parse.Promise.as(val);
},
delay: function(ms) {
var promise = new Parse.Promise();
_setTimeout(promise.resolve.bind(promise), ms);
return promise;
}
};
// There's no setTimeout in Parse cloud, but we have nextTick
function _setTimeout(fn, ms) {
var start = Date.now();
process.nextTick(fakeSetTimeout);
function fakeSetTimeout() {
if (Date.now() < start + ms) {
process.nextTick(fakeSetTimeout);
return;
}
fn();
}
}
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
/**
* This is the web browser implementation of `debug()`.
*
* Expose `debug()` as the module.
*/
exports = module.exports = __webpack_require__(2);
exports.log = log;
exports.formatArgs = formatArgs;
exports.save = save;
exports.load = load;
exports.useColors = useColors;
exports.storage = 'undefined' != typeof chrome
&& 'undefined' != typeof chrome.storage
? chrome.storage.local
: localstorage();
/**
* Colors.
*/
exports.colors = [
'lightseagreen',
'forestgreen',
'goldenrod',
'dodgerblue',
'darkorchid',
'crimson'
];
/**
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
* and the Firebug extension (any Firefox version) are known
* to support "%c" CSS customizations.
*
* TODO: add a `localStorage` variable to explicitly enable/disable colors
*/
function useColors() {
// is webkit? http://stackoverflow.com/a/16459606/376773
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
return (typeof document !== 'undefined' && 'WebkitAppearance' in document.documentElement.style) ||
// is firebug? http://stackoverflow.com/a/398120/376773
(window.console && (console.firebug || (console.exception && console.table))) ||
// is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
(navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
}
/**
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
*/
exports.formatters.j = function(v) {
try {
return JSON.stringify(v);
} catch (err) {
return '[UnexpectedJSONParseError]: ' + err.message;
}
};
/**
* Colorize log arguments if enabled.
*
* @api public
*/
function formatArgs() {
var args = arguments;
var useColors = this.useColors;
args[0] = (useColors ? '%c' : '')
+ this.namespace
+ (useColors ? ' %c' : ' ')
+ args[0]
+ (useColors ? '%c ' : ' ')
+ '+' + exports.humanize(this.diff);
if (!useColors) return args;
var c = 'color: ' + this.color;
args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
// the final "%c" is somewhat tricky, because there could be other
// arguments passed either before or after the %c, so we need to
// figure out the correct index to insert the CSS into
var index = 0;
var lastC = 0;
args[0].replace(/%[a-z%]/g, function(match) {
if ('%%' === match) return;
index++;
if ('%c' === match) {
// we only are interested in the *last* %c
// (the user may have provided their own)
lastC = index;
}
});
args.splice(lastC, 0, c);
return args;
}
/**
* Invokes `console.log()` when available.
* No-op when `console.log` is not a "function".
*
* @api public
*/
function log() {
// this hackery is required for IE8/9, where
// the `console.log` function doesn't have 'apply'
return 'object' === typeof console
&& console.log
&& Function.prototype.apply.call(console.log, console, arguments);
}
/**
* Save `namespaces`.
*
* @param {String} namespaces
* @api private
*/
function save(namespaces) {
try {
if (null == namespaces) {
exports.storage.removeItem('debug');
} else {
exports.storage.debug = namespaces;
}
} catch(e) {}
}
/**
* Load `namespaces`.
*
* @return {String} returns the previously persisted debug modes
* @api private
*/
function load() {
var r;
try {
return exports.storage.debug;
} catch(e) {}
// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
if (typeof process !== 'undefined' && 'env' in process) {
return process.env.DEBUG;
}
}
/**
* Enable namespaces listed in `localStorage.debug` initially.
*/
exports.enable(load());
/**
* Localstorage attempts to return the localstorage.
*
* This is necessary because safari throws
* when a user disables cookies/localstorage
* and you attempt to access it.
*
* @return {LocalStorage}
* @api private
*/
function localstorage(){
try {
return window.localStorage;
} catch (e) {}
}
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
/**
* This is the common logic for both the Node.js and web browser
* implementations of `debug()`.
*
* Expose `debug()` as the module.
*/
exports = module.exports = debug.debug = debug;
exports.coerce = coerce;
exports.disable = disable;
exports.enable = enable;
exports.enabled = enabled;
exports.humanize = __webpack_require__(3);
/**
* The currently active debug mode names, and names to skip.
*/
exports.names = [];
exports.skips = [];
/**
* Map of special "%n" handling functions, for the debug "format" argument.
*
* Valid key names are a single, lowercased letter, i.e. "n".
*/
exports.formatters = {};
/**
* Previously assigned color.
*/
var prevColor = 0;
/**
* Previous log timestamp.
*/
var prevTime;
/**
* Select a color.
*
* @return {Number}
* @api private
*/
function selectColor() {
return exports.colors[prevColor++ % exports.colors.length];
}
/**
* Create a debugger with the given `namespace`.
*
* @param {String} namespace
* @return {Function}
* @api public
*/
function debug(namespace) {
// define the `disabled` version
function disabled() {
}
disabled.enabled = false;
// define the `enabled` version
function enabled() {
var self = enabled;
// set `diff` timestamp
var curr = +new Date();
var ms = curr - (prevTime || curr);
self.diff = ms;
self.prev = prevTime;
self.curr = curr;
prevTime = curr;
// add the `color` if not set
if (null == self.useColors) self.useColors = exports.useColors();
if (null == self.color && self.useColors) self.color = selectColor();
var args = new Array(arguments.length);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
args[0] = exports.coerce(args[0]);
if ('string' !== typeof args[0]) {
// anything else let's inspect with %o
args = ['%o'].concat(args);
}
// apply any `formatters` transformations
var index = 0;
args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
// if we encounter an escaped % then don't increase the array index
if (match === '%%') return match;
index++;
var formatter = exports.formatters[format];
if ('function' === typeof formatter) {
var val = args[index];
match = formatter.call(self, val);
// now we need to remove `args[index]` since it's inlined in the `format`
args.splice(index, 1);
index--;
}
return match;
});
// apply env-specific formatting
args = exports.formatArgs.apply(self, args);
var logFn = enabled.log || exports.log || console.log.bind(console);
logFn.apply(self, args);
}
enabled.enabled = true;
var fn = exports.enabled(namespace) ? enabled : disabled;
fn.namespace = namespace;
return fn;
}
/**
* Enables a debug mode by namespaces. This can include modes
* separated by a colon and wildcards.
*
* @param {String} namespaces
* @api public
*/
function enable(namespaces) {
exports.save(namespaces);
var split = (namespaces || '').split(/[\s,]+/);
var len = split.length;
for (var i = 0; i < len; i++) {
if (!split[i]) continue; // ignore empty strings
namespaces = split[i].replace(/[\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
} else {
exports.names.push(new RegExp('^' + namespaces + '$'));
}
}
}
/**
* Disable debug output.
*
* @api public
*/
function disable() {
exports.enable('');
}
/**
* Returns true if the given mode name is enabled, false otherwise.
*
* @param {String} name
* @return {Boolean}
* @api public
*/
function enabled(name) {
var i, len;
for (i = 0, len = exports.skips.length; i < len; i++) {
if (exports.skips[i].test(name)) {
return false;
}
}
for (i = 0, len = exports.names.length; i < len; i++) {
if (exports.names[i].test(name)) {
return true;
}
}
return false;
}
/**
* Coerce `val`.
*
* @param {Mixed} val
* @return {Mixed}
* @api private
*/
function coerce(val) {
if (val instanceof Error) return val.stack || val.message;
return val;
}
/***/ },
/* 3 */
/***/ function(module, exports) {
/**
* Helpers.
*/
var s = 1000
var m = s * 60
var h = m * 60
var d = h * 24
var y = d * 365.25
/**
* Parse or format the given `val`.
*
* Options:
*
* - `long` verbose formatting [false]
*
* @param {String|Number} val
* @param {Object} options
* @throws {Error} throw an error if val is not a non-empty string or a number
* @return {String|Number}
* @api public
*/
module.exports = function (val, options) {
options = options || {}
var type = typeof val
if (type === 'string' && val.length > 0) {
return parse(val)
} else if (type === 'number' && isNaN(val) === false) {
return options.long ?
fmtLong(val) :
fmtShort(val)
}
throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val))
}
/**
* Parse the given `str` and return milliseconds.
*
* @param {String} str
* @return {Number}
* @api private
*/
function parse(str) {
str = String(str)
if (str.length > 10000) {
return
}
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str)
if (!match) {
return
}
var n = parseFloat(match[1])
var type = (match[2] || 'ms').toLowerCase()
switch (type) {
case 'years':
case 'year':
case 'yrs':
case 'yr':
case 'y':
return n * y
case 'days':
case 'day':
case 'd':
return n * d
case 'hours':
case 'hour':
case 'hrs':
case 'hr':
case 'h':
return n * h
case 'minutes':
case 'minute':
case 'mins':
case 'min':
case 'm':
return n * m
case 'seconds':
case 'second':
case 'secs':
case 'sec':
case 's':
return n * s
case 'milliseconds':
case 'millisecond':
case 'msecs':
case 'msec':
case 'ms':
return n
default:
return undefined
}
}
/**
* Short format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtShort(ms) {
if (ms >= d) {
return Math.round(ms / d) + 'd'
}
if (ms >= h) {
return Math.round(ms / h) + 'h'
}
if (ms >= m) {
return Math.round(ms / m) + 'm'
}
if (ms >= s) {
return Math.round(ms / s) + 's'
}
return ms + 'ms'
}
/**
* Long format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtLong(ms) {
return plural(ms, d, 'day') ||
plural(ms, h, 'hour') ||
plural(ms, m, 'minute') ||
plural(ms, s, 'second') ||
ms + ' ms'
}
/**
* Pluralization helper.
*/
function plural(ms, n, name) {
if (ms < n) {
return
}
if (ms < n * 1.5) {
return Math.floor(ms / n) + ' ' + name
}
return Math.ceil(ms / n) + ' ' + name + 's'
}
/***/ },
/* 4 */
/***/ function(module, exports) {
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
// Some methods only accessible server side
module.exports = AlgoliaSearchServer;
var inherits = __webpack_require__(4);
var AlgoliaSearch = __webpack_require__(6);
function AlgoliaSearchServer(applicationID, apiKey, opts) {
// Default protocol is https: on the server, to avoid leaking admin keys
if (opts.protocol === undefined) {
opts.protocol = 'https:';
}
AlgoliaSearch.apply(this, arguments);
}
inherits(AlgoliaSearchServer, AlgoliaSearch);
/*
* Allow to use IP rate limit when you have a proxy between end-user and Algolia.
* This option will set the X-Forwarded-For HTTP header with the client IP and the X-Forwarded-API-Key with the API Key having rate limits.
* @param adminAPIKey the admin API Key you can find in your dashboard
* @param endUserIP the end user IP (you can use both IPV4 or IPV6 syntax)
* @param rateLimitAPIKey the API key on which you have a rate limit
*/
AlgoliaSearchServer.prototype.enableRateLimitForward = function(adminAPIKey, endUserIP, rateLimitAPIKey) {
this._forward = {
adminAPIKey: adminAPIKey,
endUserIP: endUserIP,
rateLimitAPIKey: rateLimitAPIKey
};
};
/*
* Disable IP rate limit enabled with enableRateLimitForward() function
*/
AlgoliaSearchServer.prototype.disableRateLimitForward = function() {
this._forward = null;
};
/*
* Specify the securedAPIKey to use with associated information
*/
AlgoliaSearchServer.prototype.useSecuredAPIKey = function(securedAPIKey, securityTags, userToken) {
this._secure = {
apiKey: securedAPIKey,
securityTags: securityTags,
userToken: userToken
};
};
/*
* If a secured API was used, disable it
*/
AlgoliaSearchServer.prototype.disableSecuredAPIKey = function() {
this._secure = null;
};
AlgoliaSearchServer.prototype._computeRequestHeaders = function() {
var headers = AlgoliaSearchServer.super_.prototype._computeRequestHeaders.call(this);
if (this._forward) {
headers['x-algolia-api-key'] = this._forward.adminAPIKey;
headers['x-forwarded-for'] = this._forward.endUserIP;
headers['x-forwarded-api-key'] = this._forward.rateLimitAPIKey;
}
if (this._secure) {
headers['x-algolia-api-key'] = this._secure.apiKey;
headers['x-algolia-tagfilters'] = this._secure.securityTags;
headers['x-algolia-usertoken'] = this._secure.userToken;
}
return headers;
};
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
module.exports = AlgoliaSearch;
var Index = __webpack_require__(7);
var deprecate = __webpack_require__(12);
var deprecatedMessage = __webpack_require__(13);
var AlgoliaSearchCore = __webpack_require__(24);
var inherits = __webpack_require__(4);
var errors = __webpack_require__(10);
function AlgoliaSearch() {
AlgoliaSearchCore.apply(this, arguments);
}
inherits(AlgoliaSearch, AlgoliaSearchCore);
/*
* Delete an index
*
* @param indexName the name of index to delete
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer that contains the task ID
*/
AlgoliaSearch.prototype.deleteIndex = function(indexName, callback) {
return this._jsonRequest({
method: 'DELETE',
url: '/1/indexes/' + encodeURIComponent(indexName),
hostType: 'write',
callback: callback
});
};
/**
* Move an existing index.
* @param srcIndexName the name of index to copy.
* @param dstIndexName the new index name that will contains a copy of
* srcIndexName (destination will be overriten if it already exist).
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer that contains the task ID
*/
AlgoliaSearch.prototype.moveIndex = function(srcIndexName, dstIndexName, callback) {
var postObj = {
operation: 'move', destination: dstIndexName
};
return this._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation',
body: postObj,
hostType: 'write',
callback: callback
});
};
/**
* Copy an existing index.
* @param srcIndexName the name of index to copy.
* @param dstIndexName the new index name that will contains a copy
* of srcIndexName (destination will be overriten if it already exist).
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer that contains the task ID
*/
AlgoliaSearch.prototype.copyIndex = function(srcIndexName, dstIndexName, callback) {
var postObj = {
operation: 'copy', destination: dstIndexName
};
return this._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(srcIndexName) + '/operation',
body: postObj,
hostType: 'write',
callback: callback
});
};
/**
* Return last log entries.
* @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry).
* @param length Specify the maximum number of entries to retrieve starting
* at offset. Maximum allowed value: 1000.
* @param type Specify the maximum number of entries to retrieve starting
* at offset. Maximum allowed value: 1000.
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer that contains the task ID
*/
AlgoliaSearch.prototype.getLogs = function(offset, length, callback) {
var clone = __webpack_require__(15);
var params = {};
if (typeof offset === 'object') {
// getLogs(params)
params = clone(offset);
callback = length;
} else if (arguments.length === 0 || typeof offset === 'function') {
// getLogs([cb])
callback = offset;
} else if (arguments.length === 1 || typeof length === 'function') {
// getLogs(1, [cb)]
callback = length;
params.offset = offset;
} else {
// getLogs(1, 2, [cb])
params.offset = offset;
params.length = length;
}
if (params.offset === undefined) params.offset = 0;
if (params.length === undefined) params.length = 10;
return this._jsonRequest({
method: 'GET',
url: '/1/logs?' + this._getSearchParams(params, ''),
hostType: 'read',
callback: callback
});
};
/*
* List all existing indexes (paginated)
*
* @param page The page to retrieve, starting at 0.
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer with index list
*/
AlgoliaSearch.prototype.listIndexes = function(page, callback) {
var params = '';
if (page === undefined || typeof page === 'function') {
callback = page;
} else {
params = '?page=' + page;
}
return this._jsonRequest({
method: 'GET',
url: '/1/indexes' + params,
hostType: 'read',
callback: callback
});
};
/*
* Get the index object initialized
*
* @param indexName the name of index
* @param callback the result callback with one argument (the Index instance)
*/
AlgoliaSearch.prototype.initIndex = function(indexName) {
return new Index(this, indexName);
};
/*
* List all existing user keys with their associated ACLs
*
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
*/
AlgoliaSearch.prototype.listUserKeys = function(callback) {
return this._jsonRequest({
method: 'GET',
url: '/1/keys',
hostType: 'read',
callback: callback
});
};
/*
* Get ACL of a user key
*
* @param key
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
*/
AlgoliaSearch.prototype.getUserKeyACL = function(key, callback) {
return this._jsonRequest({
method: 'GET',
url: '/1/keys/' + key,
hostType: 'read',
callback: callback
});
};
/*
* Delete an existing user key
* @param key
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
*/
AlgoliaSearch.prototype.deleteUserKey = function(key, callback) {
return this._jsonRequest({
method: 'DELETE',
url: '/1/keys/' + key,
hostType: 'write',
callback: callback
});
};
/*
* Add a new global API key
*
* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that
* can contains the following values:
* - search: allow to search (https and http)
* - addObject: allows to add/update an object in the index (https only)
* - deleteObject : allows to delete an existing object (https only)
* - deleteIndex : allows to delete index content (https only)
* - settings : allows to get index settings (https only)
* - editSettings : allows to change index settings (https only)
* @param {Object} [params] - Optionnal parameters to set for the key
* @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key)
* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour
* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call
* @param {string[]} params.indexes - Allowed targeted indexes for this key
* @param {string} params.description - A description for your key
* @param {string[]} params.referers - A list of authorized referers
* @param {Object} params.queryParameters - Force the key to use specific query parameters
* @param {Function} callback - The result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
* @return {Promise|undefined} Returns a promise if no callback given
* @example
* client.addUserKey(['search'], {
* validity: 300,
* maxQueriesPerIPPerHour: 2000,
* maxHitsPerQuery: 3,
* indexes: ['fruits'],
* description: 'Eat three fruits',
* referers: ['*.algolia.com'],
* queryParameters: {
* tagFilters: ['public'],
* }
* })
* @see {@link https://www.algolia.com/doc/rest_api#AddKey|Algolia REST API Documentation}
*/
AlgoliaSearch.prototype.addUserKey = function(acls, params, callback) {
var isArray = __webpack_require__(19);
var usage = 'Usage: client.addUserKey(arrayOfAcls[, params, callback])';
if (!isArray(acls)) {
throw new Error(usage);
}
if (arguments.length === 1 || typeof params === 'function') {
callback = params;
params = null;
}
var postObj = {
acl: acls
};
if (params) {
postObj.validity = params.validity;
postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
postObj.maxHitsPerQuery = params.maxHitsPerQuery;
postObj.indexes = params.indexes;
postObj.description = params.description;
if (params.queryParameters) {
postObj.queryParameters = this._getSearchParams(params.queryParameters, '');
}
postObj.referers = params.referers;
}
return this._jsonRequest({
method: 'POST',
url: '/1/keys',
body: postObj,
hostType: 'write',
callback: callback
});
};
/**
* Add a new global API key
* @deprecated Please use client.addUserKey()
*/
AlgoliaSearch.prototype.addUserKeyWithValidity = deprecate(function(acls, params, callback) {
return this.addUserKey(acls, params, callback);
}, deprecatedMessage('client.addUserKeyWithValidity()', 'client.addUserKey()'));
/**
* Update an existing API key
* @param {string} key - The key to update
* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that
* can contains the following values:
* - search: allow to search (https and http)
* - addObject: allows to add/update an object in the index (https only)
* - deleteObject : allows to delete an existing object (https only)
* - deleteIndex : allows to delete index content (https only)
* - settings : allows to get index settings (https only)
* - editSettings : allows to change index settings (https only)
* @param {Object} [params] - Optionnal parameters to set for the key
* @param {number} params.validity - Number of seconds after which the key will be automatically removed (0 means no time limit for this key)
* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour
* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call
* @param {string[]} params.indexes - Allowed targeted indexes for this key
* @param {string} params.description - A description for your key
* @param {string[]} params.referers - A list of authorized referers
* @param {Object} params.queryParameters - Force the key to use specific query parameters
* @param {Function} callback - The result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
* @return {Promise|undefined} Returns a promise if no callback given
* @example
* client.updateUserKey('APIKEY', ['search'], {
* validity: 300,
* maxQueriesPerIPPerHour: 2000,
* maxHitsPerQuery: 3,
* indexes: ['fruits'],
* description: 'Eat three fruits',
* referers: ['*.algolia.com'],
* queryParameters: {
* tagFilters: ['public'],
* }
* })
* @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation}
*/
AlgoliaSearch.prototype.updateUserKey = function(key, acls, params, callback) {
var isArray = __webpack_require__(19);
var usage = 'Usage: client.updateUserKey(key, arrayOfAcls[, params, callback])';
if (!isArray(acls)) {
throw new Error(usage);
}
if (arguments.length === 2 || typeof params === 'function') {
callback = params;
params = null;
}
var putObj = {
acl: acls
};
if (params) {
putObj.validity = params.validity;
putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
putObj.maxHitsPerQuery = params.maxHitsPerQuery;
putObj.indexes = params.indexes;
putObj.description = params.description;
if (params.queryParameters) {
putObj.queryParameters = this._getSearchParams(params.queryParameters, '');
}
putObj.referers = params.referers;
}
return this._jsonRequest({
method: 'PUT',
url: '/1/keys/' + key,
body: putObj,
hostType: 'write',
callback: callback
});
};
/**
* Initialize a new batch of search queries
* @deprecated use client.search()
*/
AlgoliaSearch.prototype.startQueriesBatch = deprecate(function startQueriesBatchDeprecated() {
this._batch = [];
}, deprecatedMessage('client.startQueriesBatch()', 'client.search()'));
/**
* Add a search query in the batch
* @deprecated use client.search()
*/
AlgoliaSearch.prototype.addQueryInBatch = deprecate(function addQueryInBatchDeprecated(indexName, query, args) {
this._batch.push({
indexName: indexName,
query: query,
params: args
});
}, deprecatedMessage('client.addQueryInBatch()', 'client.search()'));
/**
* Launch the batch of queries using XMLHttpRequest.
* @deprecated use client.search()
*/
AlgoliaSearch.prototype.sendQueriesBatch = deprecate(function sendQueriesBatchDeprecated(callback) {
return this.search(this._batch, callback);
}, deprecatedMessage('client.sendQueriesBatch()', 'client.search()'));
/**
* Perform write operations accross multiple indexes.
*
* To reduce the amount of time spent on network round trips,
* you can create, update, or delete several objects in one call,
* using the batch endpoint (all operations are done in the given order).
*
* Available actions:
* - addObject
* - updateObject
* - partialUpdateObject
* - partialUpdateObjectNoCreate
* - deleteObject
*
* https://www.algolia.com/doc/rest_api#Indexes
* @param {Object[]} operations An array of operations to perform
* @return {Promise|undefined} Returns a promise if no callback given
* @example
* client.batch([{
* action: 'addObject',
* indexName: 'clients',
* body: {
* name: 'Bill'
* }
* }, {
* action: 'udpateObject',
* indexName: 'fruits',
* body: {
* objectID: '29138',
* name: 'banana'
* }
* }], cb)
*/
AlgoliaSearch.prototype.batch = function(operations, callback) {
var isArray = __webpack_require__(19);
var usage = 'Usage: client.batch(operations[, callback])';
if (!isArray(operations)) {
throw new Error(usage);
}
return this._jsonRequest({
method: 'POST',
url: '/1/indexes/*/batch',
body: {
requests: operations
},
hostType: 'write',
callback: callback
});
};
// environment specific methods
AlgoliaSearch.prototype.destroy = notImplemented;
AlgoliaSearch.prototype.enableRateLimitForward = notImplemented;
AlgoliaSearch.prototype.disableRateLimitForward = notImplemented;
AlgoliaSearch.prototype.useSecuredAPIKey = notImplemented;
AlgoliaSearch.prototype.disableSecuredAPIKey = notImplemented;
AlgoliaSearch.prototype.generateSecuredApiKey = notImplemented;
function notImplemented() {
var message = 'Not implemented in this environment.\n' +
'If you feel this is a mistake, write to support@algolia.com';
throw new errors.AlgoliaSearchError(message);
}
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) {
var inherits = __webpack_require__(4);
var IndexCore = __webpack_require__(8);
var deprecate = __webpack_require__(12);
var deprecatedMessage = __webpack_require__(13);
var exitPromise = __webpack_require__(21);
var errors = __webpack_require__(10);
var deprecateForwardToSlaves = deprecate(
function() {},
deprecatedMessage('forwardToSlaves', 'forwardToReplicas')
);
module.exports = Index;
function Index() {
IndexCore.apply(this, arguments);
}
inherits(Index, IndexCore);
/*
* Add an object in this index
*
* @param content contains the javascript object to add inside the index
* @param objectID (optional) an objectID you want to attribute to this object
* (if the attribute already exist the old object will be overwrite)
* @param callback (optional) the result callback called with two arguments:
* error: null or Error('message')
* content: the server answer that contains 3 elements: createAt, taskId and objectID
*/
Index.prototype.addObject = function(content, objectID, callback) {
var indexObj = this;
if (arguments.length === 1 || typeof objectID === 'function') {
callback = objectID;
objectID = undefined;
}
return this.as._jsonRequest({
method: objectID !== undefined ?
'PUT' : // update or create
'POST', // create (API generates an objectID)
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + // create
(objectID !== undefined ? '/' + encodeURIComponent(objectID) : ''), // update or create
body: content,
hostType: 'write',
callback: callback
});
};
/*
* Add several objects
*
* @param objects contains an array of objects to add
* @param callback (optional) the result callback called with two arguments:
* error: null or Error('message')
* content: the server answer that updateAt and taskID
*/
Index.prototype.addObjects = function(objects, callback) {
var isArray = __webpack_require__(19);
var usage = 'Usage: index.addObjects(arrayOfObjects[, callback])';
if (!isArray(objects)) {
throw new Error(usage);
}
var indexObj = this;
var postObj = {
requests: []
};
for (var i = 0; i < objects.length; ++i) {
var request = {
action: 'addObject',
body: objects[i]
};
postObj.requests.push(request);
}
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
body: postObj,
hostType: 'write',
callback: callback
});
};
/*
* Update partially an object (only update attributes passed in argument)
*
* @param partialObject contains the javascript attributes to override, the
* object must contains an objectID attribute
* @param createIfNotExists (optional) if false, avoid an automatic creation of the object
* @param callback (optional) the result callback called with two arguments:
* error: null or Error('message')
* content: the server answer that contains 3 elements: createAt, taskId and objectID
*/
Index.prototype.partialUpdateObject = function(partialObject, createIfNotExists, callback) {
if (arguments.length === 1 || typeof createIfNotExists === 'function') {
callback = createIfNotExists;
createIfNotExists = undefined;
}
var indexObj = this;
var url = '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(partialObject.objectID) + '/partial';
if (createIfNotExists === false) {
url += '?createIfNotExists=false';
}
return this.as._jsonRequest({
method: 'POST',
url: url,
body: partialObject,
hostType: 'write',
callback: callback
});
};
/*
* Partially Override the content of several objects
*
* @param objects contains an array of objects to update (each object must contains a objectID attribute)
* @param callback (optional) the result callback called with two arguments:
* error: null or Error('message')
* content: the server answer that updateAt and taskID
*/
Index.prototype.partialUpdateObjects = function(objects, callback) {
var isArray = __webpack_require__(19);
var usage = 'Usage: index.partialUpdateObjects(arrayOfObjects[, callback])';
if (!isArray(objects)) {
throw new Error(usage);
}
var indexObj = this;
var postObj = {
requests: []
};
for (var i = 0; i < objects.length; ++i) {
var request = {
action: 'partialUpdateObject',
objectID: objects[i].objectID,
body: objects[i]
};
postObj.requests.push(request);
}
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
body: postObj,
hostType: 'write',
callback: callback
});
};
/*
* Override the content of object
*
* @param object contains the javascript object to save, the object must contains an objectID attribute
* @param callback (optional) the result callback called with two arguments:
* error: null or Error('message')
* content: the server answer that updateAt and taskID
*/
Index.prototype.saveObject = function(object, callback) {
var indexObj = this;
return this.as._jsonRequest({
method: 'PUT',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(object.objectID),
body: object,
hostType: 'write',
callback: callback
});
};
/*
* Override the content of several objects
*
* @param objects contains an array of objects to update (each object must contains a objectID attribute)
* @param callback (optional) the result callback called with two arguments:
* error: null or Error('message')
* content: the server answer that updateAt and taskID
*/
Index.prototype.saveObjects = function(objects, callback) {
var isArray = __webpack_require__(19);
var usage = 'Usage: index.saveObjects(arrayOfObjects[, callback])';
if (!isArray(objects)) {
throw new Error(usage);
}
var indexObj = this;
var postObj = {
requests: []
};
for (var i = 0; i < objects.length; ++i) {
var request = {
action: 'updateObject',
objectID: objects[i].objectID,
body: objects[i]
};
postObj.requests.push(request);
}
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
body: postObj,
hostType: 'write',
callback: callback
});
};
/*
* Delete an object from the index
*
* @param objectID the unique identifier of object to delete
* @param callback (optional) the result callback called with two arguments:
* error: null or Error('message')
* content: the server answer that contains 3 elements: createAt, taskId and objectID
*/
Index.prototype.deleteObject = function(objectID, callback) {
if (typeof objectID === 'function' || typeof objectID !== 'string' && typeof objectID !== 'number') {
var err = new errors.AlgoliaSearchError('Cannot delete an object without an objectID');
callback = objectID;
if (typeof callback === 'function') {
return callback(err);
}
return this.as._promise.reject(err);
}
var indexObj = this;
return this.as._jsonRequest({
method: 'DELETE',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID),
hostType: 'write',
callback: callback
});
};
/*
* Delete several objects from an index
*
* @param objectIDs contains an array of objectID to delete
* @param callback (optional) the result callback called with two arguments:
* error: null or Error('message')
* content: the server answer that contains 3 elements: createAt, taskId and objectID
*/
Index.prototype.deleteObjects = function(objectIDs, callback) {
var isArray = __webpack_require__(19);
var map = __webpack_require__(20);
var usage = 'Usage: index.deleteObjects(arrayOfObjectIDs[, callback])';
if (!isArray(objectIDs)) {
throw new Error(usage);
}
var indexObj = this;
var postObj = {
requests: map(objectIDs, function prepareRequest(objectID) {
return {
action: 'deleteObject',
objectID: objectID,
body: {
objectID: objectID
}
};
})
};
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/batch',
body: postObj,
hostType: 'write',
callback: callback
});
};
/*
* Delete all objects matching a query
*
* @param query the query string
* @param params the optional query parameters
* @param callback (optional) the result callback called with one argument
* error: null or Error('message')
*/
Index.prototype.deleteByQuery = function(query, params, callback) {
var clone = __webpack_require__(15);
var map = __webpack_require__(20);
var indexObj = this;
var client = indexObj.as;
if (arguments.length === 1 || typeof params === 'function') {
callback = params;
params = {};
} else {
params = clone(params);
}
params.attributesToRetrieve = 'objectID';
params.hitsPerPage = 1000;
params.distinct = false;
// when deleting, we should never use cache to get the
// search results
this.clearCache();
// there's a problem in how we use the promise chain,
// see how waitTask is done
var promise = this
.search(query, params)
.then(stopOrDelete);
function stopOrDelete(searchContent) {
// stop here
if (searchContent.nbHits === 0) {
// return indexObj.as._request.resolve();
return searchContent;
}
// continue and do a recursive call
var objectIDs = map(searchContent.hits, function getObjectID(object) {
return object.objectID;
});
return indexObj
.deleteObjects(objectIDs)
.then(waitTask)
.then(doDeleteByQuery);
}
function waitTask(deleteObjectsContent) {
return indexObj.waitTask(deleteObjectsContent.taskID);
}
function doDeleteByQuery() {
return indexObj.deleteByQuery(query, params);
}
if (!callback) {
return promise;
}
promise.then(success, failure);
function success() {
exitPromise(function exit() {
callback(null);
}, client._setTimeout || setTimeout);
}
function failure(err) {
exitPromise(function exit() {
callback(err);
}, client._setTimeout || setTimeout);
}
};
/*
* Browse all content from an index using events. Basically this will do
* .browse() -> .browseFrom -> .browseFrom -> .. until all the results are returned
*
* @param {string} query - The full text query
* @param {Object} [queryParameters] - Any search query parameter
* @return {EventEmitter}
* @example
* var browser = index.browseAll('cool songs', {
* tagFilters: 'public,comments',
* hitsPerPage: 500
* });
*
* browser.on('result', function resultCallback(content) {
* console.log(content.hits);
* });
*
* // if any error occurs, you get it
* browser.on('error', function(err) {
* throw err;
* });
*
* // when you have browsed the whole index, you get this event
* browser.on('end', function() {
* console.log('finished');
* });
*
* // at any point if you want to stop the browsing process, you can stop it manually
* // otherwise it will go on and on
* browser.stop();
*
* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation}
*/
Index.prototype.browseAll = function(query, queryParameters) {
if (typeof query === 'object') {
queryParameters = query;
query = undefined;
}
var merge = __webpack_require__(14);
var IndexBrowser = __webpack_require__(22);
var browser = new IndexBrowser();
var client = this.as;
var index = this;
var params = client._getSearchParams(
merge({}, queryParameters || {}, {
query: query
}), ''
);
// start browsing
browseLoop();
function browseLoop(cursor) {
if (browser._stopped) {
return;
}
var queryString;
if (cursor !== undefined) {
queryString = 'cursor=' + encodeURIComponent(cursor);
} else {
queryString = params;
}
client._jsonRequest({
method: 'GET',
url: '/1/indexes/' + encodeURIComponent(index.indexName) + '/browse?' + queryString,
hostType: 'read',
callback: browseCallback
});
}
function browseCallback(err, content) {
if (browser._stopped) {
return;
}
if (err) {
browser._error(err);
return;
}
browser._result(content);
// no cursor means we are finished browsing
if (content.cursor === undefined) {
browser._end();
return;
}
browseLoop(content.cursor);
}
return browser;
};
/*
* Get a Typeahead.js adapter
* @param searchParams contains an object with query parameters (see search for details)
*/
Index.prototype.ttAdapter = function(params) {
var self = this;
return function ttAdapter(query, syncCb, asyncCb) {
var cb;
if (typeof asyncCb === 'function') {
// typeahead 0.11
cb = asyncCb;
} else {
// pre typeahead 0.11
cb = syncCb;
}
self.search(query, params, function searchDone(err, content) {
if (err) {
cb(err);
return;
}
cb(content.hits);
});
};
};
/*
* Wait the publication of a task on the server.
* All server task are asynchronous and you can check with this method that the task is published.
*
* @param taskID the id of the task returned by server
* @param callback the result callback with with two arguments:
* error: null or Error('message')
* content: the server answer that contains the list of results
*/
Index.prototype.waitTask = function(taskID, callback) {
// wait minimum 100ms before retrying
var baseDelay = 100;
// wait maximum 5s before retrying
var maxDelay = 5000;
var loop = 0;
// waitTask() must be handled differently from other methods,
// it's a recursive method using a timeout
var indexObj = this;
var client = indexObj.as;
var promise = retryLoop();
function retryLoop() {
return client._jsonRequest({
method: 'GET',
hostType: 'read',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/task/' + taskID
}).then(function success(content) {
loop++;
var delay = baseDelay * loop * loop;
if (delay > maxDelay) {
delay = maxDelay;
}
if (content.status !== 'published') {
return client._promise.delay(delay).then(retryLoop);
}
return content;
});
}
if (!callback) {
return promise;
}
promise.then(successCb, failureCb);
function successCb(content) {
exitPromise(function exit() {
callback(null, content);
}, client._setTimeout || setTimeout);
}
function failureCb(err) {
exitPromise(function exit() {
callback(err);
}, client._setTimeout || setTimeout);
}
};
/*
* This function deletes the index content. Settings and index specific API keys are kept untouched.
*
* @param callback (optional) the result callback called with two arguments
* error: null or Error('message')
* content: the settings object or the error message if a failure occured
*/
Index.prototype.clearIndex = function(callback) {
var indexObj = this;
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/clear',
hostType: 'write',
callback: callback
});
};
/*
* Get settings of this index
*
* @param callback (optional) the result callback called with two arguments
* error: null or Error('message')
* content: the settings object or the error message if a failure occured
*/
Index.prototype.getSettings = function(callback) {
var indexObj = this;
return this.as._jsonRequest({
method: 'GET',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings?getVersion=2',
hostType: 'read',
callback: callback
});
};
Index.prototype.searchSynonyms = function(params, callback) {
if (typeof params === 'function') {
callback = params;
params = {};
} else if (params === undefined) {
params = {};
}
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/search',
body: params,
hostType: 'read',
callback: callback
});
};
Index.prototype.saveSynonym = function(synonym, opts, callback) {
if (typeof opts === 'function') {
callback = opts;
opts = {};
} else if (opts === undefined) {
opts = {};
}
if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves();
var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false';
return this.as._jsonRequest({
method: 'PUT',
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(synonym.objectID) +
'?forwardToReplicas=' + forwardToReplicas,
body: synonym,
hostType: 'write',
callback: callback
});
};
Index.prototype.getSynonym = function(objectID, callback) {
return this.as._jsonRequest({
method: 'GET',
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID),
hostType: 'read',
callback: callback
});
};
Index.prototype.deleteSynonym = function(objectID, opts, callback) {
if (typeof opts === 'function') {
callback = opts;
opts = {};
} else if (opts === undefined) {
opts = {};
}
if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves();
var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false';
return this.as._jsonRequest({
method: 'DELETE',
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/' + encodeURIComponent(objectID) +
'?forwardToReplicas=' + forwardToReplicas,
hostType: 'write',
callback: callback
});
};
Index.prototype.clearSynonyms = function(opts, callback) {
if (typeof opts === 'function') {
callback = opts;
opts = {};
} else if (opts === undefined) {
opts = {};
}
if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves();
var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false';
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/clear' +
'?forwardToReplicas=' + forwardToReplicas,
hostType: 'write',
callback: callback
});
};
Index.prototype.batchSynonyms = function(synonyms, opts, callback) {
if (typeof opts === 'function') {
callback = opts;
opts = {};
} else if (opts === undefined) {
opts = {};
}
if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves();
var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false';
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/synonyms/batch' +
'?forwardToReplicas=' + forwardToReplicas +
'&replaceExistingSynonyms=' + (opts.replaceExistingSynonyms ? 'true' : 'false'),
hostType: 'write',
body: synonyms,
callback: callback
});
};
/*
* Set settings for this index
*
* @param settigns the settings object that can contains :
* - minWordSizefor1Typo: (integer) the minimum number of characters to accept one typo (default = 3).
* - minWordSizefor2Typos: (integer) the minimum number of characters to accept two typos (default = 7).
* - hitsPerPage: (integer) the number of hits per page (default = 10).
* - attributesToRetrieve: (array of strings) default list of attributes to retrieve in objects.
* If set to null, all attributes are retrieved.
* - attributesToHighlight: (array of strings) default list of attributes to highlight.
* If set to null, all indexed attributes are highlighted.
* - attributesToSnippet**: (array of strings) default list of attributes to snippet alongside the number
* of words to return (syntax is attributeName:nbWords).
* By default no snippet is computed. If set to null, no snippet is computed.
* - attributesToIndex: (array of strings) the list of fields you want to index.
* If set to null, all textual and numerical attributes of your objects are indexed,
* but you should update it to get optimal results.
* This parameter has two important uses:
* - Limit the attributes to index: For example if you store a binary image in base64,
* you want to store it and be able to
* retrieve it but you don't want to search in the base64 string.
* - Control part of the ranking*: (see the ranking parameter for full explanation)
* Matches in attributes at the beginning of
* the list will be considered more important than matches in attributes further down the list.
* In one attribute, matching text at the beginning of the attribute will be
* considered more important than text after, you can disable
* this behavior if you add your attribute inside `unordered(AttributeName)`,
* for example attributesToIndex: ["title", "unordered(text)"].
* - attributesForFaceting: (array of strings) The list of fields you want to use for faceting.
* All strings in the attribute selected for faceting are extracted and added as a facet.
* If set to null, no attribute is used for faceting.
* - attributeForDistinct: (string) The attribute name used for the Distinct feature.
* This feature is similar to the SQL "distinct" keyword: when enabled
* in query with the distinct=1 parameter, all hits containing a duplicate
* value for this attribute are removed from results.
* For example, if the chosen attribute is show_name and several hits have
* the same value for show_name, then only the best one is kept and others are removed.
* - ranking: (array of strings) controls the way results are sorted.
* We have six available criteria:
* - typo: sort according to number of typos,
* - geo: sort according to decreassing distance when performing a geo-location based search,
* - proximity: sort according to the proximity of query words in hits,
* - attribute: sort according to the order of attributes defined by attributesToIndex,
* - exact:
* - if the user query contains one word: sort objects having an attribute
* that is exactly the query word before others.
* For example if you search for the "V" TV show, you want to find it
* with the "V" query and avoid to have all popular TV
* show starting by the v letter before it.
* - if the user query contains multiple words: sort according to the
* number of words that matched exactly (and not as a prefix).
* - custom: sort according to a user defined formula set in **customRanking** attribute.
* The standard order is ["typo", "geo", "proximity", "attribute", "exact", "custom"]
* - customRanking: (array of strings) lets you specify part of the ranking.
* The syntax of this condition is an array of strings containing attributes
* prefixed by asc (ascending order) or desc (descending order) operator.
* For example `"customRanking" => ["desc(population)", "asc(name)"]`
* - queryType: Select how the query words are interpreted, it can be one of the following value:
* - prefixAll: all query words are interpreted as prefixes,
* - prefixLast: only the last word is interpreted as a prefix (default behavior),
* - prefixNone: no query word is interpreted as a prefix. This option is not recommended.
* - highlightPreTag: (string) Specify the string that is inserted before
* the highlighted parts in the query result (default to "").
* - highlightPostTag: (string) Specify the string that is inserted after
* the highlighted parts in the query result (default to "").
* - optionalWords: (array of strings) Specify a list of words that should
* be considered as optional when found in the query.
* @param callback (optional) the result callback called with two arguments
* error: null or Error('message')
* content: the server answer or the error message if a failure occured
*/
Index.prototype.setSettings = function(settings, opts, callback) {
if (arguments.length === 1 || typeof opts === 'function') {
callback = opts;
opts = {};
}
if (opts.forwardToSlaves !== undefined) deprecateForwardToSlaves();
var forwardToReplicas = (opts.forwardToSlaves || opts.forwardToReplicas) ? 'true' : 'false';
var indexObj = this;
return this.as._jsonRequest({
method: 'PUT',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/settings?forwardToReplicas='
+ forwardToReplicas,
hostType: 'write',
body: settings,
callback: callback
});
};
/*
* List all existing user keys associated to this index
*
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
*/
Index.prototype.listUserKeys = function(callback) {
var indexObj = this;
return this.as._jsonRequest({
method: 'GET',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys',
hostType: 'read',
callback: callback
});
};
/*
* Get ACL of a user key associated to this index
*
* @param key
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
*/
Index.prototype.getUserKeyACL = function(key, callback) {
var indexObj = this;
return this.as._jsonRequest({
method: 'GET',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key,
hostType: 'read',
callback: callback
});
};
/*
* Delete an existing user key associated to this index
*
* @param key
* @param callback the result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
*/
Index.prototype.deleteUserKey = function(key, callback) {
var indexObj = this;
return this.as._jsonRequest({
method: 'DELETE',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/keys/' + key,
hostType: 'write',
callback: callback
});
};
/*
* Add a new API key to this index
*
* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that
* can contains the following values:
* - search: allow to search (https and http)
* - addObject: allows to add/update an object in the index (https only)
* - deleteObject : allows to delete an existing object (https only)
* - deleteIndex : allows to delete index content (https only)
* - settings : allows to get index settings (https only)
* - editSettings : allows to change index settings (https only)
* @param {Object} [params] - Optionnal parameters to set for the key
* @param {number} params.validity - Number of seconds after which the key will
* be automatically removed (0 means no time limit for this key)
* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour
* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call
* @param {string} params.description - A description for your key
* @param {string[]} params.referers - A list of authorized referers
* @param {Object} params.queryParameters - Force the key to use specific query parameters
* @param {Function} callback - The result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
* @return {Promise|undefined} Returns a promise if no callback given
* @example
* index.addUserKey(['search'], {
* validity: 300,
* maxQueriesPerIPPerHour: 2000,
* maxHitsPerQuery: 3,
* description: 'Eat three fruits',
* referers: ['*.algolia.com'],
* queryParameters: {
* tagFilters: ['public'],
* }
* })
* @see {@link https://www.algolia.com/doc/rest_api#AddIndexKey|Algolia REST API Documentation}
*/
Index.prototype.addUserKey = function(acls, params, callback) {
var isArray = __webpack_require__(19);
var usage = 'Usage: index.addUserKey(arrayOfAcls[, params, callback])';
if (!isArray(acls)) {
throw new Error(usage);
}
if (arguments.length === 1 || typeof params === 'function') {
callback = params;
params = null;
}
var postObj = {
acl: acls
};
if (params) {
postObj.validity = params.validity;
postObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
postObj.maxHitsPerQuery = params.maxHitsPerQuery;
postObj.description = params.description;
if (params.queryParameters) {
postObj.queryParameters = this.as._getSearchParams(params.queryParameters, '');
}
postObj.referers = params.referers;
}
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys',
body: postObj,
hostType: 'write',
callback: callback
});
};
/**
* Add an existing user key associated to this index
* @deprecated use index.addUserKey()
*/
Index.prototype.addUserKeyWithValidity = deprecate(function deprecatedAddUserKeyWithValidity(acls, params, callback) {
return this.addUserKey(acls, params, callback);
}, deprecatedMessage('index.addUserKeyWithValidity()', 'index.addUserKey()'));
/**
* Update an existing API key of this index
* @param {string} key - The key to update
* @param {string[]} acls - The list of ACL for this key. Defined by an array of strings that
* can contains the following values:
* - search: allow to search (https and http)
* - addObject: allows to add/update an object in the index (https only)
* - deleteObject : allows to delete an existing object (https only)
* - deleteIndex : allows to delete index content (https only)
* - settings : allows to get index settings (https only)
* - editSettings : allows to change index settings (https only)
* @param {Object} [params] - Optionnal parameters to set for the key
* @param {number} params.validity - Number of seconds after which the key will
* be automatically removed (0 means no time limit for this key)
* @param {number} params.maxQueriesPerIPPerHour - Number of API calls allowed from an IP address per hour
* @param {number} params.maxHitsPerQuery - Number of hits this API key can retrieve in one call
* @param {string} params.description - A description for your key
* @param {string[]} params.referers - A list of authorized referers
* @param {Object} params.queryParameters - Force the key to use specific query parameters
* @param {Function} callback - The result callback called with two arguments
* error: null or Error('message')
* content: the server answer with user keys list
* @return {Promise|undefined} Returns a promise if no callback given
* @example
* index.updateUserKey('APIKEY', ['search'], {
* validity: 300,
* maxQueriesPerIPPerHour: 2000,
* maxHitsPerQuery: 3,
* description: 'Eat three fruits',
* referers: ['*.algolia.com'],
* queryParameters: {
* tagFilters: ['public'],
* }
* })
* @see {@link https://www.algolia.com/doc/rest_api#UpdateIndexKey|Algolia REST API Documentation}
*/
Index.prototype.updateUserKey = function(key, acls, params, callback) {
var isArray = __webpack_require__(19);
var usage = 'Usage: index.updateUserKey(key, arrayOfAcls[, params, callback])';
if (!isArray(acls)) {
throw new Error(usage);
}
if (arguments.length === 2 || typeof params === 'function') {
callback = params;
params = null;
}
var putObj = {
acl: acls
};
if (params) {
putObj.validity = params.validity;
putObj.maxQueriesPerIPPerHour = params.maxQueriesPerIPPerHour;
putObj.maxHitsPerQuery = params.maxHitsPerQuery;
putObj.description = params.description;
if (params.queryParameters) {
putObj.queryParameters = this.as._getSearchParams(params.queryParameters, '');
}
putObj.referers = params.referers;
}
return this.as._jsonRequest({
method: 'PUT',
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/keys/' + key,
body: putObj,
hostType: 'write',
callback: callback
});
};
/***/ },
/* 8 */
/***/ function(module, exports, __webpack_require__) {
var buildSearchMethod = __webpack_require__(9);
var deprecate = __webpack_require__(12);
var deprecatedMessage = __webpack_require__(13);
module.exports = IndexCore;
/*
* Index class constructor.
* You should not use this method directly but use initIndex() function
*/
function IndexCore(algoliasearch, indexName) {
this.indexName = indexName;
this.as = algoliasearch;
this.typeAheadArgs = null;
this.typeAheadValueOption = null;
// make sure every index instance has it's own cache
this.cache = {};
}
/*
* Clear all queries in cache
*/
IndexCore.prototype.clearCache = function() {
this.cache = {};
};
/*
* Search inside the index using XMLHttpRequest request (Using a POST query to
* minimize number of OPTIONS queries: Cross-Origin Resource Sharing).
*
* @param query the full text query
* @param args (optional) if set, contains an object with query parameters:
* - page: (integer) Pagination parameter used to select the page to retrieve.
* Page is zero-based and defaults to 0. Thus,
* to retrieve the 10th page you need to set page=9
* - hitsPerPage: (integer) Pagination parameter used to select the number of hits per page. Defaults to 20.
* - attributesToRetrieve: a string that contains the list of object attributes
* you want to retrieve (let you minimize the answer size).
* Attributes are separated with a comma (for example "name,address").
* You can also use an array (for example ["name","address"]).
* By default, all attributes are retrieved. You can also use '*' to retrieve all
* values when an attributesToRetrieve setting is specified for your index.
* - attributesToHighlight: a string that contains the list of attributes you
* want to highlight according to the query.
* Attributes are separated by a comma. You can also use an array (for example ["name","address"]).
* If an attribute has no match for the query, the raw value is returned.
* By default all indexed text attributes are highlighted.
* You can use `*` if you want to highlight all textual attributes.
* Numerical attributes are not highlighted.
* A matchLevel is returned for each highlighted attribute and can contain:
* - full: if all the query terms were found in the attribute,
* - partial: if only some of the query terms were found,
* - none: if none of the query terms were found.
* - attributesToSnippet: a string that contains the list of attributes to snippet alongside
* the number of words to return (syntax is `attributeName:nbWords`).
* Attributes are separated by a comma (Example: attributesToSnippet=name:10,content:10).
* You can also use an array (Example: attributesToSnippet: ['name:10','content:10']).
* By default no snippet is computed.
* - minWordSizefor1Typo: the minimum number of characters in a query word to accept one typo in this word.
* Defaults to 3.
* - minWordSizefor2Typos: the minimum number of characters in a query word
* to accept two typos in this word. Defaults to 7.
* - getRankingInfo: if set to 1, the result hits will contain ranking
* information in _rankingInfo attribute.
* - aroundLatLng: search for entries around a given
* latitude/longitude (specified as two floats separated by a comma).
* For example aroundLatLng=47.316669,5.016670).
* You can specify the maximum distance in meters with the aroundRadius parameter (in meters)
* and the precision for ranking with aroundPrecision
* (for example if you set aroundPrecision=100, two objects that are distant of
* less than 100m will be considered as identical for "geo" ranking parameter).
* At indexing, you should specify geoloc of an object with the _geoloc attribute
* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}})
* - insideBoundingBox: search entries inside a given area defined by the two extreme points
* of a rectangle (defined by 4 floats: p1Lat,p1Lng,p2Lat,p2Lng).
* For example insideBoundingBox=47.3165,4.9665,47.3424,5.0201).
* At indexing, you should specify geoloc of an object with the _geoloc attribute
* (in the form {"_geoloc":{"lat":48.853409, "lng":2.348800}})
* - numericFilters: a string that contains the list of numeric filters you want to
* apply separated by a comma.
* The syntax of one filter is `attributeName` followed by `operand` followed by `value`.
* Supported operands are `<`, `<=`, `=`, `>` and `>=`.
* You can have multiple conditions on one attribute like for example numericFilters=price>100,price<1000.
* You can also use an array (for example numericFilters: ["price>100","price<1000"]).
* - tagFilters: filter the query by a set of tags. You can AND tags by separating them by commas.
* To OR tags, you must add parentheses. For example, tags=tag1,(tag2,tag3) means tag1 AND (tag2 OR tag3).
* You can also use an array, for example tagFilters: ["tag1",["tag2","tag3"]]
* means tag1 AND (tag2 OR tag3).
* At indexing, tags should be added in the _tags** attribute
* of objects (for example {"_tags":["tag1","tag2"]}).
* - facetFilters: filter the query by a list of facets.
* Facets are separated by commas and each facet is encoded as `attributeName:value`.
* For example: `facetFilters=category:Book,author:John%20Doe`.
* You can also use an array (for example `["category:Book","author:John%20Doe"]`).
* - facets: List of object attributes that you want to use for faceting.
* Comma separated list: `"category,author"` or array `['category','author']`
* Only attributes that have been added in **attributesForFaceting** index setting
* can be used in this parameter.
* You can also use `*` to perform faceting on all attributes specified in **attributesForFaceting**.
* - queryType: select how the query words are interpreted, it can be one of the following value:
* - prefixAll: all query words are interpreted as prefixes,
* - prefixLast: only the last word is interpreted as a prefix (default behavior),
* - prefixNone: no query word is interpreted as a prefix. This option is not recommended.
* - optionalWords: a string that contains the list of words that should
* be considered as optional when found in the query.
* Comma separated and array are accepted.
* - distinct: If set to 1, enable the distinct feature (disabled by default)
* if the attributeForDistinct index setting is set.
* This feature is similar to the SQL "distinct" keyword: when enabled
* in a query with the distinct=1 parameter,
* all hits containing a duplicate value for the attributeForDistinct attribute are removed from results.
* For example, if the chosen attribute is show_name and several hits have
* the same value for show_name, then only the best
* one is kept and others are removed.
* - restrictSearchableAttributes: List of attributes you want to use for
* textual search (must be a subset of the attributesToIndex index setting)
* either comma separated or as an array
* @param callback the result callback called with two arguments:
* error: null or Error('message'). If false, the content contains the error.
* content: the server answer that contains the list of results.
*/
IndexCore.prototype.search = buildSearchMethod('query');
/*
* -- BETA --
* Search a record similar to the query inside the index using XMLHttpRequest request (Using a POST query to
* minimize number of OPTIONS queries: Cross-Origin Resource Sharing).
*
* @param query the similar query
* @param args (optional) if set, contains an object with query parameters.
* All search parameters are supported (see search function), restrictSearchableAttributes and facetFilters
* are the two most useful to restrict the similar results and get more relevant content
*/
IndexCore.prototype.similarSearch = buildSearchMethod('similarQuery');
/*
* Browse index content. The response content will have a `cursor` property that you can use
* to browse subsequent pages for this query. Use `index.browseFrom(cursor)` when you want.
*
* @param {string} query - The full text query
* @param {Object} [queryParameters] - Any search query parameter
* @param {Function} [callback] - The result callback called with two arguments
* error: null or Error('message')
* content: the server answer with the browse result
* @return {Promise|undefined} Returns a promise if no callback given
* @example
* index.browse('cool songs', {
* tagFilters: 'public,comments',
* hitsPerPage: 500
* }, callback);
* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation}
*/
IndexCore.prototype.browse = function(query, queryParameters, callback) {
var merge = __webpack_require__(14);
var indexObj = this;
var page;
var hitsPerPage;
// we check variadic calls that are not the one defined
// .browse()/.browse(fn)
// => page = 0
if (arguments.length === 0 || arguments.length === 1 && typeof arguments[0] === 'function') {
page = 0;
callback = arguments[0];
query = undefined;
} else if (typeof arguments[0] === 'number') {
// .browse(2)/.browse(2, 10)/.browse(2, fn)/.browse(2, 10, fn)
page = arguments[0];
if (typeof arguments[1] === 'number') {
hitsPerPage = arguments[1];
} else if (typeof arguments[1] === 'function') {
callback = arguments[1];
hitsPerPage = undefined;
}
query = undefined;
queryParameters = undefined;
} else if (typeof arguments[0] === 'object') {
// .browse(queryParameters)/.browse(queryParameters, cb)
if (typeof arguments[1] === 'function') {
callback = arguments[1];
}
queryParameters = arguments[0];
query = undefined;
} else if (typeof arguments[0] === 'string' && typeof arguments[1] === 'function') {
// .browse(query, cb)
callback = arguments[1];
queryParameters = undefined;
}
// otherwise it's a .browse(query)/.browse(query, queryParameters)/.browse(query, queryParameters, cb)
// get search query parameters combining various possible calls
// to .browse();
queryParameters = merge({}, queryParameters || {}, {
page: page,
hitsPerPage: hitsPerPage,
query: query
});
var params = this.as._getSearchParams(queryParameters, '');
return this.as._jsonRequest({
method: 'GET',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/browse?' + params,
hostType: 'read',
callback: callback
});
};
/*
* Continue browsing from a previous position (cursor), obtained via a call to `.browse()`.
*
* @param {string} query - The full text query
* @param {Object} [queryParameters] - Any search query parameter
* @param {Function} [callback] - The result callback called with two arguments
* error: null or Error('message')
* content: the server answer with the browse result
* @return {Promise|undefined} Returns a promise if no callback given
* @example
* index.browseFrom('14lkfsakl32', callback);
* @see {@link https://www.algolia.com/doc/rest_api#Browse|Algolia REST API Documentation}
*/
IndexCore.prototype.browseFrom = function(cursor, callback) {
return this.as._jsonRequest({
method: 'GET',
url: '/1/indexes/' + encodeURIComponent(this.indexName) + '/browse?cursor=' + encodeURIComponent(cursor),
hostType: 'read',
callback: callback
});
};
/*
* Search for facet values
* https://www.algolia.com/doc/rest-api/search#search-for-facet-values
*
* @param {string} params.facetName Facet name, name of the attribute to search for values in.
* Must be declared as a facet
* @param {string} params.facetQuery Query for the facet search
* @param {string} [params.*] Any search parameter of Algolia,
* see https://www.algolia.com/doc/api-client/javascript/search#search-parameters
* Pagination is not supported. The page and hitsPerPage parameters will be ignored.
* @param callback (optional)
*/
IndexCore.prototype.searchForFacetValues = function(params, callback) {
var clone = __webpack_require__(15);
var omit = __webpack_require__(16);
var usage = 'Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])';
if (params.facetName === undefined || params.facetQuery === undefined) {
throw new Error(usage);
}
var facetName = params.facetName;
var filteredParams = omit(clone(params), function(keyName) {
return keyName === 'facetName';
});
var searchParameters = this.as._getSearchParams(filteredParams, '');
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/' +
encodeURIComponent(this.indexName) + '/facets/' + encodeURIComponent(facetName) + '/query',
hostType: 'read',
body: {params: searchParameters},
callback: callback
});
};
IndexCore.prototype.searchFacet = deprecate(function(params, callback) {
return this.searchForFacetValues(params, callback);
}, deprecatedMessage(
'index.searchFacet(params[, callback])',
'index.searchForFacetValues(params[, callback])'
));
IndexCore.prototype._search = function(params, url, callback) {
return this.as._jsonRequest({
cache: this.cache,
method: 'POST',
url: url || '/1/indexes/' + encodeURIComponent(this.indexName) + '/query',
body: {params: params},
hostType: 'read',
fallback: {
method: 'GET',
url: '/1/indexes/' + encodeURIComponent(this.indexName),
body: {params: params}
},
callback: callback
});
};
/*
* Get an object from this index
*
* @param objectID the unique identifier of the object to retrieve
* @param attrs (optional) if set, contains the array of attribute names to retrieve
* @param callback (optional) the result callback called with two arguments
* error: null or Error('message')
* content: the object to retrieve or the error message if a failure occured
*/
IndexCore.prototype.getObject = function(objectID, attrs, callback) {
var indexObj = this;
if (arguments.length === 1 || typeof attrs === 'function') {
callback = attrs;
attrs = undefined;
}
var params = '';
if (attrs !== undefined) {
params = '?attributes=';
for (var i = 0; i < attrs.length; ++i) {
if (i !== 0) {
params += ',';
}
params += attrs[i];
}
}
return this.as._jsonRequest({
method: 'GET',
url: '/1/indexes/' + encodeURIComponent(indexObj.indexName) + '/' + encodeURIComponent(objectID) + params,
hostType: 'read',
callback: callback
});
};
/*
* Get several objects from this index
*
* @param objectIDs the array of unique identifier of objects to retrieve
*/
IndexCore.prototype.getObjects = function(objectIDs, attributesToRetrieve, callback) {
var isArray = __webpack_require__(19);
var map = __webpack_require__(20);
var usage = 'Usage: index.getObjects(arrayOfObjectIDs[, callback])';
if (!isArray(objectIDs)) {
throw new Error(usage);
}
var indexObj = this;
if (arguments.length === 1 || typeof attributesToRetrieve === 'function') {
callback = attributesToRetrieve;
attributesToRetrieve = undefined;
}
var body = {
requests: map(objectIDs, function prepareRequest(objectID) {
var request = {
indexName: indexObj.indexName,
objectID: objectID
};
if (attributesToRetrieve) {
request.attributesToRetrieve = attributesToRetrieve.join(',');
}
return request;
})
};
return this.as._jsonRequest({
method: 'POST',
url: '/1/indexes/*/objects',
hostType: 'read',
body: body,
callback: callback
});
};
IndexCore.prototype.as = null;
IndexCore.prototype.indexName = null;
IndexCore.prototype.typeAheadArgs = null;
IndexCore.prototype.typeAheadValueOption = null;
/***/ },
/* 9 */
/***/ function(module, exports, __webpack_require__) {
module.exports = buildSearchMethod;
var errors = __webpack_require__(10);
function buildSearchMethod(queryParam, url) {
return function search(query, args, callback) {
// warn V2 users on how to search
if (typeof query === 'function' && typeof args === 'object' ||
typeof callback === 'object') {
// .search(query, params, cb)
// .search(cb, params)
throw new errors.AlgoliaSearchError('index.search usage is index.search(query, params, cb)');
}
if (arguments.length === 0 || typeof query === 'function') {
// .search(), .search(cb)
callback = query;
query = '';
} else if (arguments.length === 1 || typeof args === 'function') {
// .search(query/args), .search(query, cb)
callback = args;
args = undefined;
}
// .search(args), careful: typeof null === 'object'
if (typeof query === 'object' && query !== null) {
args = query;
query = undefined;
} else if (query === undefined || query === null) { // .search(undefined/null)
query = '';
}
var params = '';
if (query !== undefined) {
params += queryParam + '=' + encodeURIComponent(query);
}
if (args !== undefined) {
// `_getSearchParams` will augment params, do not be fooled by the = versus += from previous if
params = this.as._getSearchParams(args, params);
}
return this._search(params, url, callback);
};
}
/***/ },
/* 10 */
/***/ function(module, exports, __webpack_require__) {
// This file hosts our error definitions
// We use custom error "types" so that we can act on them when we need it
// e.g.: if error instanceof errors.UnparsableJSON then..
var inherits = __webpack_require__(4);
function AlgoliaSearchError(message, extraProperties) {
var forEach = __webpack_require__(11);
var error = this;
// try to get a stacktrace
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
error.stack = (new Error()).stack || 'Cannot get a stacktrace, browser is too old';
}
this.name = 'AlgoliaSearchError';
this.message = message || 'Unknown error';
if (extraProperties) {
forEach(extraProperties, function addToErrorObject(value, key) {
error[key] = value;
});
}
}
inherits(AlgoliaSearchError, Error);
function createCustomError(name, message) {
function AlgoliaSearchCustomError() {
var args = Array.prototype.slice.call(arguments, 0);
// custom message not set, use default
if (typeof args[0] !== 'string') {
args.unshift(message);
}
AlgoliaSearchError.apply(this, args);
this.name = 'AlgoliaSearch' + name + 'Error';
}
inherits(AlgoliaSearchCustomError, AlgoliaSearchError);
return AlgoliaSearchCustomError;
}
// late exports to let various fn defs and inherits take place
module.exports = {
AlgoliaSearchError: AlgoliaSearchError,
UnparsableJSON: createCustomError(
'UnparsableJSON',
'Could not parse the incoming response as JSON, see err.more for details'
),
RequestTimeout: createCustomError(
'RequestTimeout',
'Request timedout before getting a response'
),
Network: createCustomError(
'Network',
'Network issue, see err.more for details'
),
JSONPScriptFail: createCustomError(
'JSONPScriptFail',
'