(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1) { return displayName + " (" + userId + ")"; } else { return displayName; } }, /* * High level helper method to call initialSync, emit the resulting events, * and then start polling the eventStream for new events. * @param {function} callback Callback invoked whenever new event are available * @param {Number} historyLen amount of historical timeline events to * emit during from the initial sync. */ startClient: function(callback, historyLen) { historyLen = historyLen || 12; var self = this; if (!this.fromToken) { this._http.initialSync(historyLen, function(err, data) { var i, j; if (err) { if (this.config && this.config.debug) { console.error( "startClient error on initialSync: %s", JSON.stringify(err) ); } callback(err); return; } if (self.store) { var eventMapper = function(event) { return new MatrixEvent(event); }; // intercept the results and put them into our store self.store.setPresenceEvents( utils.map(data.presence, eventMapper) ); for (i = 0; i < data.rooms.length; i++) { self.store.setStateEvents( utils.map(data.rooms[i].state, eventMapper) ); self.store.setEvents( utils.map(data.rooms[i].messages.chunk, eventMapper) ); } } if (data) { self.fromToken = data.end; var events = []; for (i = 0; i < data.presence.length; i++) { events.push(new MatrixEvent(data.presence[i])); } for (i = 0; i < data.rooms.length; i++) { for (j = 0; j < data.rooms[i].state.length; j++) { events.push(new MatrixEvent(data.rooms[i].state[j])); } for (j = 0; j < data.rooms[i].messages.chunk.length; j++) { events.push( new MatrixEvent(data.rooms[i].messages.chunk[j]) ); } } callback(undefined, events, false); } self.clientRunning = true; self._pollForEvents(callback); }); } else { this._pollForEvents(callback); } }, _pollForEvents: function(callback) { var self = this; if (!this.clientRunning) { return; } this._http.eventStream(this.fromToken, 30000, function(err, data) { if (err) { if (this.config && this.config.debug) { console.error( "error polling for events via eventStream: %s", JSON.stringify(err) ); } callback(err); // retry every few seconds // FIXME: this should be exponential backoff with an option to nudge setTimeout(function() { self._pollForEvents(callback); }, 2000); return; } if (self.store) { self.store.setEvents(utils.map(data.chunk, function(event) { return new MatrixEvent(event); } )); } if (data) { self.fromToken = data.end; var events = []; for (var j = 0; j < data.chunk.length; j++) { events.push(new MatrixEvent(data.chunk[j])); } callback(undefined, events, true); } self._pollForEvents(callback); }); }, /* * High level helper method to stop the client from polling and allow a * clean shutdown. */ stopClient: function() { this.clientRunning = false; }, }; /** * The high-level Matrix Client class. */ module.exports = MatrixClient; // expose the class },{"./http-api":2,"./models/event":4,"./utils":6}],2:[function(require,module,exports){ "use strict"; var utils = require("./utils"); /* TODO: - CS: complete register function (doing stages) - Identity server: linkEmail, authEmail, bindEmail, lookup3pid - uploadContent (?) */ /** * A constant representing the URI path for version 1 of the Client-Server HTTP API. */ module.exports.PREFIX_V1 = "/_matrix/client/api/v1"; /** * A constant representing the URI path for version 2 Alpha of the Client-Server * HTTP API. */ module.exports.PREFIX_V2_ALPHA_PREFIX = "/_matrix/client/v2_alpha"; var HEADERS = { "User-Agent": "matrix-js" }; /** * Construct a MatrixHttpApi. * @constructor * @param {Object} opts The options to use for this HTTP API. * @param {string} opts.baseUrl Required. The base client-server URL e.g. * 'http://localhost:8008'. * @param {Function} opts.request Required. The function to call for HTTP * requests. This function must look like function(opts, callback){ ... }. * @param {string} opts.prefix Required. The matrix client prefix to use, e.g. * '/_matrix/client/api/v1'. See PREFIX_V1 and PREFIX_V2_ALPHA for constants. * @param {boolean} opts.setUserAgent True to set a user-agent string on requests. * Default: True, unless there is a 'window' global present in which case the default * is False. * @param {string} opts.accessToken The access_token to send with requests. Can be * null to not send an access token. */ function MatrixHttpApi(opts) { utils.checkObjectHasKeys(opts, ["baseUrl", "request", "prefix"]); this.opts = opts; } MatrixHttpApi.prototype = { // URI functions // ============= getHttpUriForMxc: function(mxc, width, height, resizeMethod) { if (typeof mxc !== "string" || !mxc) { return mxc; } if (mxc.indexOf("mxc://") !== 0) { return mxc; } var serverAndMediaId = mxc.slice(6); // strips mxc:// var prefix = "/_matrix/media/v1/download/"; var params = {}; if (width) { params.width = width; } if (height) { params.height = height; } if (resizeMethod) { params.method = resizeMethod; } if (Object.keys(params).length > 0) { // these are thumbnailing params so they probably want the // thumbnailing API... prefix = "/_matrix/media/v1/thumbnail/"; } var fragmentOffset = serverAndMediaId.indexOf("#"), fragment = ""; if (fragmentOffset >= 0) { fragment = serverAndMediaId.substr(fragmentOffset); serverAndMediaId = serverAndMediaId.substr(0, fragmentOffset); } return this.credentials.baseUrl + prefix + serverAndMediaId + (Object.keys(params).length === 0 ? "" : ("?" + utils.encodeParams(params))) + fragment; }, getIdenticonUri: function(identiconString, width, height) { if (!identiconString) { return; } if (!width) { width = 96; } if (!height) { height = 96; } var params = { width: width, height: height }; var path = utils.encodeUri("/_matrix/media/v1/identicon/$ident", { $ident: identiconString }); return this.credentials.baseUrl + path + (Object.keys(params).length === 0 ? "" : ("?" + utils.encodeParams(params))); }, /** * Get the content repository url with query parameters. * @return {Object} An object with a 'base', 'path' and 'params' for base URL, * path and query parameters respectively. */ getContentUri: function() { var params = { access_token: this.credentials.accessToken }; return { base: this.credentials.baseUrl, path: "/_matrix/media/v1/upload", params: params }; }, authedRequest: function(callback, method, path, queryParams, data) { if (!queryParams) { queryParams = {}; } queryParams.access_token = this.opts.accessToken; return this.request(callback, method, path, queryParams, data); }, request: function(callback, method, path, queryParams, data) { return this.requestWithPrefix( callback, method, path, queryParams, data, this.opts.prefix ); }, authedRequestWithPrefix: function(callback, method, path, queryParams, data, prefix) { var fullUri = this.opts.baseUrl + prefix + path; if (!queryParams) { queryParams = {}; } queryParams.access_token = this.opts.accessToken; return this._request(callback, method, fullUri, queryParams, data); }, requestWithPrefix: function(callback, method, path, queryParams, data, prefix) { var fullUri = this.opts.baseUrl + prefix + path; if (!queryParams) { queryParams = {}; } return this._request(callback, method, fullUri, queryParams, data); }, _request: function(callback, method, uri, queryParams, data) { if (callback !== undefined && !utils.isFunction(callback)) { throw Error( "Expected callback to be a function but got " + typeof callback ); } return this.opts.request( { uri: uri, method: method, withCredentials: false, qs: queryParams, body: data, json: true, headers: HEADERS, _matrix_opts: this.opts }, requestCallback(callback) ); } }; var requestCallback = function(userDefinedCallback) { if (!userDefinedCallback) { return undefined; } return function(err, response, body) { if (err) { return userDefinedCallback(err); } if (response.statusCode >= 400) { return userDefinedCallback(body); } else { userDefinedCallback(null, body); } }; }; /** * The Matrix HTTP API class. */ module.exports.MatrixHttpApi = MatrixHttpApi; },{"./utils":6}],3:[function(require,module,exports){ "use strict"; /** The Matrix Event class */ module.exports.MatrixEvent = require("./models/event").MatrixEvent; /** An in-memory store for the SDK */ module.exports.MatrixInMemoryStore = require("./store/memory"); /** The raw HTTP API */ module.exports.MatrixHttpApi = require("./http-api"); /** The managed client class */ module.exports.MatrixClient = require("./client"); // expose the underlying request object so different environments can use // different request libs (e.g. request or browser-request) var request; /** * The function used to perform HTTP requests. * @param {Function} r The request function which accepts (opts, callback) */ module.exports.request = function(r) { request = r; }; /** * Construct a Matrix Client. Identical to {@link client/MatrixClient} except * the 'request' option is already specified. * @param {(Object|string)} opts The configuration options for this client. If * this is a string, it is assumed to be the base URL. * @param {string} opts.baseUrl The base URL to the client-server HTTP API. * @param {boolean} opts.usePromises True to use promises rather than callbacks. * @param {string} opts.accessToken The access_token for this user. * @param {string} opts.userId The user ID for this user. * @return {MatrixClient} A new matrix client. */ module.exports.createClient = function(opts) { if (typeof opts === "string") { opts = { "baseUrl": opts }; } opts.request = request; return new module.exports.MatrixClient(opts); }; },{"./client":1,"./http-api":2,"./models/event":4,"./store/memory":5}],4:[function(require,module,exports){ "use strict"; /* * Construct a Matrix Event object * @param {Object} event The raw event to be wrapped in this DAO */ function MatrixEvent(event) { this.event = event || {}; } MatrixEvent.prototype = { getId: function() { return this.event.event_id; }, getSender: function() { return this.event.user_id; }, getType: function() { return this.event.type; }, getRoomId: function() { return this.event.room_id; }, getTs: function() { return this.event.ts; }, getContent: function() { return this.event.content; }, isState: function() { return this.event.state_key !== undefined; }, }; /** * An event from Matrix. */ module.exports.MatrixEvent = MatrixEvent; },{}],5:[function(require,module,exports){ "use strict"; function MatrixInMemoryStore() { this.rooms = { // state: { }, // timeline: [ ], }; this.presence = { // presence objects keyed by userId }; } // XXX: this is currently quite procedural - we could possibly pass back // models of Rooms, Users, Events, etc instead. MatrixInMemoryStore.prototype = { /* * Add an array of one or more state MatrixEvents into the store, overwriting * any existing state with the same {room, type, stateKey} tuple. */ setStateEvents: function(stateEvents) { // we store stateEvents indexed by room, event type and state key. for (var i = 0; i < stateEvents.length; i++) { var event = stateEvents[i].event; var roomId = event.room_id; if (this.rooms[roomId] === undefined) { this.rooms[roomId] = {}; } if (this.rooms[roomId].state === undefined) { this.rooms[roomId].state = {}; } if (this.rooms[roomId].state[event.type] === undefined) { this.rooms[roomId].state[event.type] = {}; } this.rooms[roomId].state[event.type][event.state_key] = stateEvents[i]; } }, /* * Add a single state MatrixEvents into the store, overwriting * any existing state with the same {room, type, stateKey} tuple. */ setStateEvent: function(stateEvent) { this.setStateEvents([stateEvent]); }, /* * Return a list of MatrixEvents from the store * @param {String} roomId the Room ID whose state is to be returned * @param {String} type the type of the state events to be returned (optional) * @param {String} stateKey the stateKey of the state events to be returned * (optional, requires type to be specified) * @return {MatrixEvent[]} an array of MatrixEvents from the store, * filtered by roomid, type and state key. */ getStateEvents: function(roomId, type, stateKey) { var stateEvents = []; if (stateKey === undefined && type === undefined) { for (type in this.rooms[roomId].state) { if (this.rooms[roomId].state.hasOwnProperty(type)) { for (stateKey in this.rooms[roomId].state[type]) { if (this.rooms[roomId].state[type].hasOwnProperty(stateKey)) { stateEvents.push( this.rooms[roomId].state[type][stateKey] ); } } } } return stateEvents; } else if (stateKey === undefined) { for (stateKey in this.rooms[roomId].state[type]) { if (this.rooms[roomId].state[type].hasOwnProperty(stateKey)) { stateEvents.push(this.rooms[roomId].state[type][stateKey]); } } return stateEvents; } else { return [this.rooms[roomId].state[type][stateKey]]; } }, /* * Return a single state MatrixEvent from the store for the given roomId * and type. * @param {String} roomId the Room ID whose state is to be returned * @param {String} type the type of the state events to be returned * @param {String} stateKey the stateKey of the state events to be returned * @return {MatrixEvent} a single MatrixEvent from the store, filtered * by roomid, type and state key. */ getStateEvent: function(roomId, type, stateKey) { return this.rooms[roomId].state[type][stateKey]; }, /* * Adds a list of arbitrary MatrixEvents into the store. * If the event is a state event, it is also updates state. */ setEvents: function(events) { for (var i = 0; i < events.length; i++) { var event = events[i].event; if (event.type === "m.presence") { this.setPresenceEvents([events[i]]); continue; } var roomId = event.room_id; if (this.rooms[roomId] === undefined) { this.rooms[roomId] = {}; } if (this.rooms[roomId].timeline === undefined) { this.rooms[roomId].timeline = []; } if (event.state_key !== undefined) { this.setStateEvents([events[i]]); } this.rooms[roomId].timeline.push(events[i]); } }, /* * Get the timeline of events for a given room * TODO: ordering! */ getEvents: function(roomId) { return this.room[roomId].timeline; }, setPresenceEvents: function(presenceEvents) { for (var i = 0; i < presenceEvents.length; i++) { var matrixEvent = presenceEvents[i]; this.presence[matrixEvent.event.user_id] = matrixEvent; } }, getPresenceEvents: function(userId) { return this.presence[userId]; }, getRoomList: function() { var roomIds = []; for (var roomId in this.rooms) { if (this.rooms.hasOwnProperty(roomId)) { roomIds.push(roomId); } } return roomIds; }, // TODO //setMaxHistoryPerRoom: function(maxHistory) {}, // TODO //reapOldMessages: function() {}, }; /** * An in-memory store for Matrix. */ module.exports = MatrixInMemoryStore; },{}],6:[function(require,module,exports){ "use strict"; /** * Encode a dictionary of query parameters. * @param {Object} params A dict of key/values to encode e.g. * {"foo": "bar", "baz": "taz"} * @return {string} The encoded string e.g. foo=bar&baz=taz */ module.exports.encodeParams = function(params) { var qs = ""; for (var key in params) { if (!params.hasOwnProperty(key)) { continue; } qs += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(params[key]); } return qs.substring(1); }; /** * Encodes a URI according to a set of template variables. Variables will be * passed through encodeURIComponent. * @param {string} pathTemplate The path with template variables e.g. '/foo/$bar'. * @param {Object} variables The key/value pairs to replace the template * variables with. E.g. { "$bar": "baz" }. * @return {string} The result of replacing all template variables e.g. '/foo/baz'. */ module.exports.encodeUri = function(pathTemplate, variables) { for (var key in variables) { if (!variables.hasOwnProperty(key)) { continue; } pathTemplate = pathTemplate.replace( key, encodeURIComponent(variables[key]) ); } return pathTemplate; }; /** * Applies a map function to the given array. * @param {Array} array The array to apply the function to. * @param {Function} fn The function that will be invoked for each element in * the array. * @return {Array} A new array with the results of the function. */ module.exports.map = function(array, fn) { var results = new Array(array.length); for (var i = 0; i < array.length; i++) { results[i] = fn(array[i]); } return results; }; /** * Checks if the given thing is a function. * @param {*} value The thing to check. * @return {boolean} True if it is a function. */ module.exports.isFunction = function(value) { return Object.prototype.toString.call(value) == "[object Function]"; }; /** * Checks that the given object has the specified keys. * @param {Object} obj The object to check. * @param {string[]} keys The list of keys that 'obj' must have. * @throws If the object is missing keys. */ module.exports.checkObjectHasKeys = function(obj, keys) { for (var i = 0; i < keys.length; i++) { if (!obj.hasOwnProperty(keys[i])) { throw new Error("Missing required key: " + keys[i]); } } }; /** * Checks that the given object has no extra keys other than the specified ones. * @param {Object} obj The object to check. * @param {string[]} allowedKeys The list of allowed key names. * @throws If there are extra keys. */ module.exports.checkObjectHasNoAdditionalKeys = function(obj, allowedKeys) { for (var key in obj) { if (!obj.hasOwnProperty(key)) { continue; } if (allowedKeys.indexOf(key) === -1) { throw new Error("Unknown key: " + key); } } }; },{}],7:[function(require,module,exports){ // Browser Request // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // UMD HEADER START (function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define([], factory); } else if (typeof exports === 'object') { // Node. Does not work with strict CommonJS, but // only CommonJS-like enviroments that support module.exports, // like Node. module.exports = factory(); } else { // Browser globals (root is window) root.returnExports = factory(); } }(this, function () { // UMD HEADER END var XHR = XMLHttpRequest if (!XHR) throw new Error('missing XMLHttpRequest') request.log = { 'trace': noop, 'debug': noop, 'info': noop, 'warn': noop, 'error': noop } var DEFAULT_TIMEOUT = 3 * 60 * 1000 // 3 minutes // // request // function request(options, callback) { // The entry-point to the API: prep the options object and pass the real work to run_xhr. if(typeof callback !== 'function') throw new Error('Bad callback given: ' + callback) if(!options) throw new Error('No options given') var options_onResponse = options.onResponse; // Save this for later. if(typeof options === 'string') options = {'uri':options}; else options = JSON.parse(JSON.stringify(options)); // Use a duplicate for mutating. options.onResponse = options_onResponse // And put it back. if (options.verbose) request.log = getLogger(); if(options.url) { options.uri = options.url; delete options.url; } if(!options.uri && options.uri !== "") throw new Error("options.uri is a required argument"); if(typeof options.uri != "string") throw new Error("options.uri must be a string"); var unsupported_options = ['proxy', '_redirectsFollowed', 'maxRedirects', 'followRedirect'] for (var i = 0; i < unsupported_options.length; i++) if(options[ unsupported_options[i] ]) throw new Error("options." + unsupported_options[i] + " is not supported") options.callback = callback options.method = options.method || 'GET'; options.headers = options.headers || {}; options.body = options.body || null options.timeout = options.timeout || request.DEFAULT_TIMEOUT if(options.headers.host) throw new Error("Options.headers.host is not supported"); if(options.json) { options.headers.accept = options.headers.accept || 'application/json' if(options.method !== 'GET') options.headers['content-type'] = 'application/json' if(typeof options.json !== 'boolean') options.body = JSON.stringify(options.json) else if(typeof options.body !== 'string') options.body = JSON.stringify(options.body) } //BEGIN QS Hack var serialize = function(obj) { var str = []; for(var p in obj) if (obj.hasOwnProperty(p)) { str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); } return str.join("&"); } if(options.qs){ var qs = (typeof options.qs == 'string')? options.qs : serialize(options.qs); if(options.uri.indexOf('?') !== -1){ //no get params options.uri = options.uri+'&'+qs; }else{ //existing get params options.uri = options.uri+'?'+qs; } } //END QS Hack //BEGIN FORM Hack var multipart = function(obj) { //todo: support file type (useful?) var result = {}; result.boundry = '-------------------------------'+Math.floor(Math.random()*1000000000); var lines = []; for(var p in obj){ if (obj.hasOwnProperty(p)) { lines.push( '--'+result.boundry+"\n"+ 'Content-Disposition: form-data; name="'+p+'"'+"\n"+ "\n"+ obj[p]+"\n" ); } } lines.push( '--'+result.boundry+'--' ); result.body = lines.join(''); result.length = result.body.length; result.type = 'multipart/form-data; boundary='+result.boundry; return result; } if(options.form){ if(typeof options.form == 'string') throw('form name unsupported'); if(options.method === 'POST'){ var encoding = (options.encoding || 'application/x-www-form-urlencoded').toLowerCase(); options.headers['content-type'] = encoding; switch(encoding){ case 'application/x-www-form-urlencoded': options.body = serialize(options.form).replace(/%20/g, "+"); break; case 'multipart/form-data': var multi = multipart(options.form); //options.headers['content-length'] = multi.length; options.body = multi.body; options.headers['content-type'] = multi.type; break; default : throw new Error('unsupported encoding:'+encoding); } } } //END FORM Hack // If onResponse is boolean true, call back immediately when the response is known, // not when the full request is complete. options.onResponse = options.onResponse || noop if(options.onResponse === true) { options.onResponse = callback options.callback = noop } // XXX Browsers do not like this. //if(options.body) // options.headers['content-length'] = options.body.length; // HTTP basic authentication if(!options.headers.authorization && options.auth) options.headers.authorization = 'Basic ' + b64_enc(options.auth.username + ':' + options.auth.password); return run_xhr(options) } var req_seq = 0 function run_xhr(options) { var xhr = new XHR , timed_out = false , is_cors = is_crossDomain(options.uri) , supports_cors = ('withCredentials' in xhr) req_seq += 1 xhr.seq_id = req_seq xhr.id = req_seq + ': ' + options.method + ' ' + options.uri xhr._id = xhr.id // I know I will type "_id" from habit all the time. if(is_cors && !supports_cors) { var cors_err = new Error('Browser does not support cross-origin request: ' + options.uri) cors_err.cors = 'unsupported' return options.callback(cors_err, xhr) } xhr.timeoutTimer = setTimeout(too_late, options.timeout) function too_late() { timed_out = true var er = new Error('ETIMEDOUT') er.code = 'ETIMEDOUT' er.duration = options.timeout request.log.error('Timeout', { 'id':xhr._id, 'milliseconds':options.timeout }) return options.callback(er, xhr) } // Some states can be skipped over, so remember what is still incomplete. var did = {'response':false, 'loading':false, 'end':false} xhr.onreadystatechange = on_state_change xhr.open(options.method, options.uri, true) // asynchronous if(is_cors) xhr.withCredentials = !! options.withCredentials xhr.send(options.body) return xhr function on_state_change(event) { if(timed_out) return request.log.debug('Ignoring timed out state change', {'state':xhr.readyState, 'id':xhr.id}) request.log.debug('State change', {'state':xhr.readyState, 'id':xhr.id, 'timed_out':timed_out}) if(xhr.readyState === XHR.OPENED) { request.log.debug('Request started', {'id':xhr.id}) for (var key in options.headers) xhr.setRequestHeader(key, options.headers[key]) } else if(xhr.readyState === XHR.HEADERS_RECEIVED) on_response() else if(xhr.readyState === XHR.LOADING) { on_response() on_loading() } else if(xhr.readyState === XHR.DONE) { on_response() on_loading() on_end() } } function on_response() { if(did.response) return did.response = true request.log.debug('Got response', {'id':xhr.id, 'status':xhr.status}) clearTimeout(xhr.timeoutTimer) xhr.statusCode = xhr.status // Node request compatibility // Detect failed CORS requests. if(is_cors && xhr.statusCode == 0) { var cors_err = new Error('CORS request rejected: ' + options.uri) cors_err.cors = 'rejected' // Do not process this request further. did.loading = true did.end = true return options.callback(cors_err, xhr) } options.onResponse(null, xhr) } function on_loading() { if(did.loading) return did.loading = true request.log.debug('Response body loading', {'id':xhr.id}) // TODO: Maybe simulate "data" events by watching xhr.responseText } function on_end() { if(did.end) return did.end = true request.log.debug('Request done', {'id':xhr.id}) xhr.body = xhr.responseText if(options.json) { try { xhr.body = JSON.parse(xhr.responseText) } catch (er) { return options.callback(er, xhr) } } options.callback(null, xhr, xhr.body) } } // request request.withCredentials = false; request.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT; // // defaults // request.defaults = function(options, requester) { var def = function (method) { var d = function (params, callback) { if(typeof params === 'string') params = {'uri': params}; else { params = JSON.parse(JSON.stringify(params)); } for (var i in options) { if (params[i] === undefined) params[i] = options[i] } return method(params, callback) } return d } var de = def(request) de.get = def(request.get) de.post = def(request.post) de.put = def(request.put) de.head = def(request.head) return de } // // HTTP method shortcuts // var shortcuts = [ 'get', 'put', 'post', 'head' ]; shortcuts.forEach(function(shortcut) { var method = shortcut.toUpperCase(); var func = shortcut.toLowerCase(); request[func] = function(opts) { if(typeof opts === 'string') opts = {'method':method, 'uri':opts}; else { opts = JSON.parse(JSON.stringify(opts)); opts.method = method; } var args = [opts].concat(Array.prototype.slice.apply(arguments, [1])); return request.apply(this, args); } }) // // CouchDB shortcut // request.couch = function(options, callback) { if(typeof options === 'string') options = {'uri':options} // Just use the request API to do JSON. options.json = true if(options.body) options.json = options.body delete options.body callback = callback || noop var xhr = request(options, couch_handler) return xhr function couch_handler(er, resp, body) { if(er) return callback(er, resp, body) if((resp.statusCode < 200 || resp.statusCode > 299) && body.error) { // The body is a Couch JSON object indicating the error. er = new Error('CouchDB error: ' + (body.error.reason || body.error.error)) for (var key in body) er[key] = body[key] return callback(er, resp, body); } return callback(er, resp, body); } } // // Utility // function noop() {} function getLogger() { var logger = {} , levels = ['trace', 'debug', 'info', 'warn', 'error'] , level, i for(i = 0; i < levels.length; i++) { level = levels[i] logger[level] = noop if(typeof console !== 'undefined' && console && console[level]) logger[level] = formatted(console, level) } return logger } function formatted(obj, method) { return formatted_logger function formatted_logger(str, context) { if(typeof context === 'object') str += ' ' + JSON.stringify(context) return obj[method].call(obj, str) } } // Return whether a URL is a cross-domain request. function is_crossDomain(url) { var rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/ // jQuery #8138, IE may throw an exception when accessing // a field from window.location if document.domain has been set var ajaxLocation try { ajaxLocation = location.href } catch (e) { // Use the href attribute of an A element since IE will modify it given document.location ajaxLocation = document.createElement( "a" ); ajaxLocation.href = ""; ajaxLocation = ajaxLocation.href; } var ajaxLocParts = rurl.exec(ajaxLocation.toLowerCase()) || [] , parts = rurl.exec(url.toLowerCase() ) var result = !!( parts && ( parts[1] != ajaxLocParts[1] || parts[2] != ajaxLocParts[2] || (parts[3] || (parts[1] === "http:" ? 80 : 443)) != (ajaxLocParts[3] || (ajaxLocParts[1] === "http:" ? 80 : 443)) ) ) //console.debug('is_crossDomain('+url+') -> ' + result) return result } // MIT License from http://phpjs.org/functions/base64_encode:358 function b64_enc (data) { // Encodes string using MIME base64 algorithm var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc="", tmp_arr = []; if (!data) { return data; } // assume utf8 data // data = this.utf8_encode(data+''); do { // pack three octets into four hexets o1 = data.charCodeAt(i++); o2 = data.charCodeAt(i++); o3 = data.charCodeAt(i++); bits = o1<<16 | o2<<8 | o3; h1 = bits>>18 & 0x3f; h2 = bits>>12 & 0x3f; h3 = bits>>6 & 0x3f; h4 = bits & 0x3f; // use hexets to index into b64, and append result to encoded string tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); } while (i < data.length); enc = tmp_arr.join(''); switch (data.length % 3) { case 1: enc = enc.slice(0, -2) + '=='; break; case 2: enc = enc.slice(0, -1) + '='; break; } return enc; } return request; //UMD FOOTER START })); //UMD FOOTER END },{}],8:[function(require,module,exports){ (function (global){ var matrixcs = require("./lib/matrix"); matrixcs.request(require("browser-request")); module.exports = matrixcs; // keep export for browserify package deps global.matrixcs = matrixcs; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./lib/matrix":3,"browser-request":7}]},{},[8]);